﻿' LibWowArmory
' by Ronald M. Clifford (roncli@roncli.com)
'
' This source code is released under the GNU Library General Public License (LGPL) Version 2.1.

Imports System.Collections.Generic
Imports Microsoft.VisualBasic
Imports roncliProductions.LibWowArmory
Imports System
Imports System.Linq

Public Module modMain

    Public Sub Main()
        ' There are a number of things to test here, so we will give the user the option of which test to perform.
        Do
            Console.WriteLine("Please choose a test to perform")
            Console.WriteLine("  Or press enter to quit.")
            Console.WriteLine("1 - Calendar")
            Console.WriteLine("2 - Character Achievements")
            Console.WriteLine("3 - Character Reputation")
            Console.WriteLine("4 - Character Search")
            Console.WriteLine("5 - Character Sheet")
            Console.WriteLine("6 - Character Statistics")
            Console.WriteLine("7 - Character Talents")
            Console.WriteLine("8 - Dungeons")
            Console.WriteLine("9 - Factions")
            Console.WriteLine("10 - Item Info")
            Console.WriteLine("11 - Item Search")
            Console.Write(">")
            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Exit Do
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                Select Case intResponse
                    Case 1
                        CalendarDemo()
                    Case 2
                        CharacterAchievementsDemo()
                    Case 3
                        CharacterReputationDemo()
                    Case 4
                        CharacterSearchDemo()
                    Case 5
                        CharacterSheetDemo()
                    Case 6
                        CharacterStatisticsDemo()
                    Case 7
                        CharacterTalentsDemo()
                    Case 8
                        DungeonDemo()
                    Case 9
                        FactionsDemo()
                    Case 10
                        ItemInfoDemo()
                    Case 11
                        ItemSearchDemo()
                End Select
                Console.Clear()
            Else
                Console.WriteLine("Invalid response.")
                Console.WriteLine()
            End If
        Loop
    End Sub

    Private Sub CalendarDemo()
        Console.Clear()
        Console.WriteLine("Calendar Demo")
        Console.WriteLine()

        ' Declare some variables
        Dim strUsername As String
        Dim strPassword As String = String.Empty
        Dim strCharacter As String
        Dim strRealm As String

        ' First, get the username
        Do
            Console.WriteLine("Please enter your World of Warcraft/Battle.Net account user name.")
            Console.Write(">")
            strUsername = Console.ReadLine()

            If String.IsNullOrEmpty(strUsername) Then
                Console.WriteLine("You must enter a username.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        ' Next, get the password
        Do
            Console.WriteLine("Please enter your password.")
            Console.Write(">")
            Do
                Dim ckiKey As ConsoleKeyInfo = Console.ReadKey(True)
                If ckiKey.Key = ConsoleKey.Enter Then Exit Do
                strPassword = String.Format("{0}{1}", strPassword, ckiKey.KeyChar)
            Loop
            Console.WriteLine()
            If String.IsNullOrEmpty(strPassword) Then
                Console.WriteLine("You must enter a password.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        ' Next, get the character
        Do
            Console.WriteLine("Please enter the name of the character whose calendar you wish to retrieve.")
            Console.Write(">")
            strCharacter = Console.ReadLine()

            If String.IsNullOrEmpty(strCharacter) Then
                Console.WriteLine("You must enter a character name.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        ' Next, get the realm
        Do
            Console.WriteLine("Please enter the name of the character's realm.")
            Console.Write(">")
            strRealm = Console.ReadLine()

            If String.IsNullOrEmpty(strRealm) Then
                Console.WriteLine("You must enter a realm.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        ' Get the events for this month
        Dim cmwBattlegrounds As New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, Date.Now, CalendarType.BattlegroundHolidays)
        Dim cmwDarkmoon As New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, Date.Now, CalendarType.DarkmoonFaire)
        Dim cmwRaidLockouts As New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, Date.Now, CalendarType.RaidLockouts)
        Dim cmwRaidResets As New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, Date.Now, CalendarType.RaidResets)
        Dim cmwWeeklyHolidays As New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, Date.Now, CalendarType.WeeklyHolidays)
        Dim cmwWorldHolidays As New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, Date.Now, CalendarType.WorldHolidays)
        Dim cmuCalendar As New CalendarMonthUser(strUsername, strPassword, strRealm, strCharacter, Date.Now)


        Do
            ' Show the calendar for this month
            Console.Clear()
            Console.WriteLine("Events for {0}-{1} for the month of {2:MMMM, yyyy}", strRealm, strCharacter, cmuCalendar.Month)
            Console.WriteLine("Calendar Type: {0}", cmuCalendar.CalendarType)
            Console.WriteLine("Timezone Offset: {0}", cmuCalendar.TimezoneOffset)
            Console.WriteLine()

            ' List this month's events
            Console.WriteLine("Battleground Holidays")
            For Each eEvent As CalendarMonthWorld.Event In cmwBattlegrounds.Events.OrderBy(Function(e) e.Start)
                Console.WriteLine("{0}-{1} - {2}", eEvent.Start, eEvent.End, eEvent.Summary)
            Next
            Console.WriteLine()

            Console.WriteLine("Darkmoon Faire")
            For Each eEvent As CalendarMonthWorld.Event In cmwDarkmoon.Events.OrderBy(Function(e) e.Start)
                Console.WriteLine("{0}-{1} - {2}", eEvent.Start, eEvent.End, eEvent.Summary)
            Next
            Console.WriteLine()

            Console.WriteLine("Raid Lockouts")
            For Each eEvent As CalendarMonthWorld.Event In cmwRaidLockouts.Events.OrderBy(Function(e) e.Start)
                Console.WriteLine("{0}-{1} - {2}", eEvent.Start, eEvent.End, eEvent.Summary)
            Next
            Console.WriteLine()

            Console.WriteLine("Raid Resets")
            For Each eEvent As CalendarMonthWorld.Event In cmwRaidResets.Events.OrderBy(Function(e) e.Start)
                Console.WriteLine("{0}-{1} - {2}", eEvent.Start, eEvent.End, eEvent.Summary)
            Next
            Console.WriteLine()

            Console.WriteLine("Weekly Holidays")
            For Each eEvent As CalendarMonthWorld.Event In cmwWeeklyHolidays.Events.OrderBy(Function(e) e.Start)
                Console.WriteLine("{0}-{1} - {2}", eEvent.Start, eEvent.End, eEvent.Summary)
            Next
            Console.WriteLine()

            Console.WriteLine("World Holidays")
            For Each eEvent As CalendarMonthWorld.Event In cmwWorldHolidays.Events.OrderBy(Function(e) e.Start)
                Console.WriteLine("{0}-{1} - {2}", eEvent.Start, eEvent.End, eEvent.Summary)
            Next
            Console.WriteLine()

            Console.WriteLine("Player Events")
            For Each eEvent As CalendarMonthUser.Event In cmuCalendar.Events.OrderBy(Function(e) e.Start)
                Console.WriteLine("{0} - {1} - {2} - {3}", eEvent.ID, eEvent.Start, eEvent.Type, eEvent.Summary)
            Next
            Console.WriteLine()

            Do
                ' Prompt to show event detail, change months, or exit
                Console.WriteLine("Enter the event ID to show the detail for that event")
                Console.WriteLine("  or enter NEXT for next month")
                Console.WriteLine("  or enter PREV for previous month")
                Console.WriteLine("  or press enter to quit")
                Console.Write(">")
                Dim strResponse As String = Console.ReadLine()
                Dim intResponse As Integer
                If Integer.TryParse(strResponse, intResponse) Then
                    CalendarDetail(strUsername, strPassword, strRealm, strCharacter, intResponse)
                    Exit Do
                Else
                    If String.IsNullOrEmpty(strResponse) Then
                        Exit Sub
                    End If
                    Select Case strResponse.ToLower
                        Case "next"
                            cmwBattlegrounds = New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, cmwBattlegrounds.Month.AddMonths(1), CalendarType.BattlegroundHolidays)
                            cmwDarkmoon = New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, cmwDarkmoon.Month.AddMonths(1), CalendarType.DarkmoonFaire)
                            cmwRaidLockouts = New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, cmwRaidLockouts.Month.AddMonths(1), CalendarType.RaidLockouts)
                            cmwRaidResets = New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, cmwRaidResets.Month.AddMonths(1), CalendarType.RaidResets)
                            cmwWeeklyHolidays = New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, cmwWeeklyHolidays.Month.AddMonths(1), CalendarType.WeeklyHolidays)
                            cmwWorldHolidays = New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, cmwWorldHolidays.Month.AddMonths(1), CalendarType.WorldHolidays)
                            cmuCalendar = New CalendarMonthUser(strUsername, strPassword, strRealm, strCharacter, cmuCalendar.Month.AddMonths(1))
                            Exit Do
                        Case "prev"
                            cmwBattlegrounds = New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, cmwBattlegrounds.Month.AddMonths(-1), CalendarType.BattlegroundHolidays)
                            cmwDarkmoon = New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, cmwDarkmoon.Month.AddMonths(-1), CalendarType.DarkmoonFaire)
                            cmwRaidLockouts = New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, cmwRaidLockouts.Month.AddMonths(-1), CalendarType.RaidLockouts)
                            cmwRaidResets = New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, cmwRaidResets.Month.AddMonths(-1), CalendarType.RaidResets)
                            cmwWeeklyHolidays = New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, cmwWeeklyHolidays.Month.AddMonths(-1), CalendarType.WeeklyHolidays)
                            cmwWorldHolidays = New CalendarMonthWorld(strUsername, strPassword, strRealm, strCharacter, cmwWorldHolidays.Month.AddMonths(-1), CalendarType.WorldHolidays)
                            cmuCalendar = New CalendarMonthUser(strUsername, strPassword, strRealm, strCharacter, cmuCalendar.Month.AddMonths(-1))
                            Exit Do
                        Case Else
                            Console.WriteLine("Invalid response.")
                            Console.WriteLine()
                    End Select
                End If
            Loop
        Loop
    End Sub

    Private Sub CalendarDetail(ByVal strUsername As String, ByVal strPassword As String, ByVal strRealm As String, ByVal strCharacter As String, ByVal intEventID As Integer)
        ' Get event detail
        Dim cdCalendar As New CalendarDetail(strUsername, strPassword, strRealm, strCharacter, intEventID)

        ' Disply event detail
        Console.Clear()
        Console.WriteLine("{0} - {1}", cdCalendar.Start, cdCalendar.Summary)
        Console.WriteLine()
        Console.WriteLine("Type: {0}", cdCalendar.Type)
        Console.WriteLine("Location: {0}", cdCalendar.Location)
        Console.WriteLine("Owner: {0}", cdCalendar.Owner)
        Console.WriteLine("Timezone Offset: {0}", cdCalendar.TimezoneOffset)
        Console.WriteLine()
        Console.WriteLine(cdCalendar.Description)
        Console.WriteLine()
        For Each iInvitee As CalendarDetail.Invitee In cdCalendar.Invitees.OrderBy(Function(i) i.Invitee)
            Console.WriteLine("{0} - {1} {2} - {3}", iInvitee.Invitee, [Enum].GetName(GetType(Enums.RaceType), iInvitee.Race), [Enum].GetName(GetType(Enums.ClassType), iInvitee.Class), iInvitee.Status)
        Next
        Console.WriteLine()

        Console.WriteLine("Press any key to continue.")
        Console.ReadKey(True)
    End Sub

    Private Sub CharacterAchievementsDemo()
        Console.Clear()
        Console.WriteLine("Character Achievements Demo")
        Console.WriteLine()

        Dim strCharacter As String
        Dim strRealm As String

        ' First, get the character
        Do
            Console.WriteLine("Please enter the name of the character whose achievements you wish to retrieve.")
            Console.Write(">")
            strCharacter = Console.ReadLine()

            If String.IsNullOrEmpty(strCharacter) Then
                Console.WriteLine("You must enter a character name.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        ' Next, get the realm
        Do
            Console.WriteLine("Please enter the name of the character's realm.")
            Console.Write(">")
            strRealm = Console.ReadLine()

            If String.IsNullOrEmpty(strRealm) Then
                Console.WriteLine("You must enter a realm.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        Dim caAchievements As New CharacterAchievements(strRealm, strCharacter)

        ' Display the achievements
        Do
            Console.Clear()
            Console.WriteLine("Achievements for {0}-{1}", strRealm, strCharacter)
            Console.WriteLine("{0}/{1} achievements earned - {2} points/{3}", caAchievements.AchievementsEarned, caAchievements.AchievementsTotal, caAchievements.AchievementPointsEarned, caAchievements.AchievementPointsTotal)

            If caAchievements.RecentAchievements.Count > 0 Then
                Console.WriteLine()
                Console.WriteLine("Most recent achievements:")
                For Each aAchievement As Achievement In caAchievements.RecentAchievements
                    Console.WriteLine("{0} - {1} - {2}", aAchievement.DateCompleted, aAchievement.Title, aAchievement.Desc)
                Next
            End If

            Console.WriteLine()
            Console.WriteLine("Select a category")
            Console.WriteLine("  or press enter to exit")
            For Each cCategory As CharacterAchievements.Category In caAchievements.Categories
                If cCategory.TotalPoints = 0 Then
                    Console.WriteLine("{0}) {1}", caAchievements.Categories.IndexOf(cCategory), cCategory.Name)
                Else
                    Console.WriteLine("{0}) {1} - {2}/{3} - {4} points/{5}", caAchievements.Categories.IndexOf(cCategory), cCategory.Name, cCategory.Earned, cCategory.Total, cCategory.EarnedPoints, cCategory.TotalPoints)
                End If
            Next

            Console.Write(">")
            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Exit Do
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse < caAchievements.Categories.Count Then
                    Console.Clear()
                    AchievementCategoryDetail(caAchievements.Categories(intResponse), caAchievements.CategoryAchievements(caAchievements.Categories(intResponse)).Achievements)
                    Console.WriteLine()
                    Console.WriteLine("Press any key to continue.")
                    Console.ReadKey(True)
                End If
            End If
        Loop
    End Sub

    Private Sub AchievementCategoryDetail(ByRef cCategory As CharacterAchievements.Category, ByRef cacCategory As CharacterAchievementsCategory.Category)
        Console.WriteLine("{0} achievements", cCategory.Name)
        Console.WriteLine()
        For Each aAchievement As Achievement In cacCategory.Achievements
            AchievementDetail(aAchievement)
            Console.WriteLine()
        Next
        For Each cSubcategory As CharacterAchievementsCategory.Category In cacCategory.Subcategories
            AchievementSubcategoryDetail(cCategory.Subcategories(cacCategory.Subcategories.IndexOf(cSubcategory)), cSubcategory)
        Next
    End Sub

    Private Sub AchievementSubcategoryDetail(ByRef sCategory As CharacterAchievements.Subcategory, ByRef cacCategory As CharacterAchievementsCategory.Category)
        Console.WriteLine("{0} achievements", sCategory.Name)
        Console.WriteLine()
        For Each aAchievement As Achievement In cacCategory.Achievements
            AchievementDetail(aAchievement)
            Console.WriteLine()
        Next
    End Sub

    Private Sub AchievementDetail(ByRef aAchievement As Achievement)
        Console.WriteLine("{0} - {1}", aAchievement.Title, aAchievement.Desc)
        If aAchievement.DateCompleted <> Date.MinValue Then
            If aAchievement.Points > 0 Then
                Console.WriteLine("Completed {0} - {1} points", aAchievement.DateCompleted, aAchievement.Points)
            Else
                Console.WriteLine("Completed {0}", aAchievement.DateCompleted)
            End If
        Else
            If aAchievement.Points > 0 Then
                Console.WriteLine("{0} points", aAchievement.Points)
            End If
        End If
        If Not String.IsNullOrEmpty(aAchievement.Reward) Then
            Console.WriteLine("Rewards {0}", aAchievement.Reward)
        End If
        For Each cCriteria As Achievement.Criteria In aAchievement.AchievementCriteria
            If Not String.IsNullOrEmpty(cCriteria.Name) Then
                Console.Write("- {0} ", cCriteria.Name)
            End If
            If aAchievement.DateCompleted = Date.MinValue And cCriteria.Date <> Date.MinValue Then
                Console.Write("- Completed {0} ", cCriteria.Date)
            End If
            If aAchievement.DateCompleted = Date.MinValue Then
                If cCriteria.MaxQuantity > 0 Then
                    Console.Write("- {0}/{1} ", cCriteria.Quantity, cCriteria.MaxQuantity)
                End If
                If cCriteria.MaxQuantityCurrency > 0 Then
                    Console.Write("- {0}g {1}s {2}c/{3}g {4}s {5}c ", Math.Floor(cCriteria.QuantityCurrency / 10000), Math.Floor(cCriteria.QuantityCurrency / 100) Mod 100, cCriteria.QuantityCurrency Mod 100, Math.Floor(cCriteria.MaxQuantityCurrency / 10000), Math.Floor(cCriteria.MaxQuantityCurrency / 100) Mod 100, cCriteria.MaxQuantityCurrency Mod 100)
                End If
            Else
                If cCriteria.MaxQuantity > 0 Then
                    Console.Write("- {0}/{0} ", cCriteria.MaxQuantity)
                End If
                If cCriteria.MaxQuantityCurrency > 0 Then
                    Console.Write("- {0}g {1}s {2}c/{0}g {1}s {2}c ", Math.Floor(cCriteria.MaxQuantityCurrency / 10000), Math.Floor(cCriteria.MaxQuantityCurrency / 100) Mod 100, cCriteria.MaxQuantityCurrency Mod 100)
                End If
            End If
            Console.WriteLine()
        Next
        If aAchievement.PreviousAchievements.Count > 0 Then
            Console.WriteLine("Previous achievements in this series:")
            For Each aPreviousAchievement As Achievement In aAchievement.PreviousAchievements
                AchievementDetail(aPreviousAchievement)
            Next
        End If
    End Sub

    Private Sub CharacterReputationDemo()
        Console.Clear()
        Console.WriteLine("Character Reputation Demo")
        Console.WriteLine()

        Dim strCharacter As String
        Dim strRealm As String

        ' First, get the character
        Do
            Console.WriteLine("Please enter the name of the character whose reputation you wish to retrieve.")
            Console.Write(">")
            strCharacter = Console.ReadLine()

            If String.IsNullOrEmpty(strCharacter) Then
                Console.WriteLine("You must enter a character name.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        ' Next, get the realm
        Do
            Console.WriteLine("Please enter the name of the character's realm.")
            Console.Write(">")
            strRealm = Console.ReadLine()

            If String.IsNullOrEmpty(strRealm) Then
                Console.WriteLine("You must enter a realm.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        Dim crReputation As New CharacterReputation(strRealm, strCharacter)

        ' Disply reputation
        Console.Clear()
        Console.WriteLine("Reputations for {0}-{1}", strRealm, strCharacter)
        Console.WriteLine()
        For Each rReputation As Reputation In crReputation.Reputation
            ListReputations(rReputation, 0)
        Next

        Console.WriteLine()
        Console.WriteLine("Press any key to continue.")
        Console.ReadKey(True)
    End Sub

    Private Sub ListReputations(ByVal rReputation As Reputation, ByVal intParents As Integer)
        If rReputation.Status = "None" Then
            Console.WriteLine("{0}{1}", StrDup(intParents, "  "), rReputation.Name)
        Else
            Console.WriteLine("{0}{1} - {2}/{3} {4}", StrDup(intParents, "  "), rReputation.Name, rReputation.Reputation, rReputation.MaxReputation, rReputation.Status)
        End If

        If rReputation.Reputations IsNot Nothing Then
            For Each rChildReputation As Reputation In rReputation.Reputations
                ListReputations(rChildReputation, intParents + 1)
            Next
        End If
    End Sub

    Private Sub CharacterSearchDemo()
        Console.Clear()
        Console.WriteLine("Character Search Demo")
        Console.WriteLine()

        Dim strCharacter As String

        ' Get the search text
        Do
            Console.WriteLine("Please enter the text you wish to search for.")
            Console.Write(">")
            strCharacter = Console.ReadLine()

            If String.IsNullOrEmpty(strCharacter) Then
                Console.WriteLine("You must enter some search text.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        ' Do the search
        Dim csSearch As New CharacterSearch(strCharacter)

        ' Display the results
        Console.Clear()
        Console.WriteLine("Character Search Results for {0}", strCharacter)
        Console.WriteLine()
        If csSearch.Characters Is Nothing Then
            Console.WriteLine("No Results")
        ElseIf csSearch.Characters.Count = 0 Then
            Console.WriteLine("No Results")
        Else
            For Each cCharacter As CharacterSearch.Character In csSearch.Characters
                Console.WriteLine("{0} - {1} - {2} - {3} - {4} {5}", cCharacter.Name, cCharacter.Realm, cCharacter.Level, cCharacter.Guild, [Enum].GetName(GetType(Enums.RaceType), cCharacter.Race), [Enum].GetName(GetType(Enums.ClassType), cCharacter.Class))
            Next
        End If

        Console.WriteLine()
        Console.WriteLine("Press any key to continue.")
        Console.ReadKey(True)
    End Sub

    Private Sub CharacterSheetDemo()
        Console.Clear()
        Console.WriteLine("Character Sheet Demo")
        Console.WriteLine()

        Dim strCharacter As String
        Dim strRealm As String

        ' First, get the character
        Do
            Console.WriteLine("Please enter the name of the character you wish to retrieve.")
            Console.Write(">")
            strCharacter = Console.ReadLine()

            If String.IsNullOrEmpty(strCharacter) Then
                Console.WriteLine("You must enter a character name.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        ' Next, get the realm
        Do
            Console.WriteLine("Please enter the name of the character's realm.")
            Console.Write(">")
            strRealm = Console.ReadLine()

            If String.IsNullOrEmpty(strRealm) Then
                Console.WriteLine("You must enter a realm.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        ' Do the lookup
        Dim csSheet As New CharacterSheet(strRealm, strCharacter)

        ' Display the results
        Console.Clear()
        Console.WriteLine("Character Sheet for {0}-{1}", strRealm, strCharacter)
        Console.WriteLine("Last Updated {0}", csSheet.LastModified)
        Console.WriteLine()

        Console.WriteLine("{0}{1}{2} - {3} - Level {4} {5} {6} {7}", csSheet.Prefix, csSheet.Name, csSheet.Suffix, csSheet.GuildName, csSheet.Level, [Enum].GetName(GetType(Enums.GenderType), csSheet.Gender), [Enum].GetName(GetType(Enums.RaceType), csSheet.Race), [Enum].GetName(GetType(Enums.ClassType), csSheet.Class))
        Console.WriteLine("Realm {0} - Battlegroup {1}", csSheet.Realm, csSheet.BattleGroup)
        Console.WriteLine()

        Console.WriteLine("Main Spec: {0} {1}/{2}/{3}", csSheet.PrimaryTalentSpec, csSheet.PrimaryTalentPoints(1), csSheet.PrimaryTalentPoints(2), csSheet.PrimaryTalentPoints(3))
        If csSheet.SecondaryTalentSpec <> "n/a" Then
            Console.WriteLine("Dual Spec: {0} {1}/{2}/{3}", csSheet.SecondaryTalentSpec, csSheet.SecondaryTalentPoints(1), csSheet.SecondaryTalentPoints(2), csSheet.SecondaryTalentPoints(3))
        End If
        Console.WriteLine()

        For Each pProfession As CharacterSheet.Profession In csSheet.Professions
            Console.WriteLine("{0}: {1}/{2}", pProfession.Name, pProfession.Skill, pProfession.Max)
        Next
        If csSheet.Professions.Count > 0 Then
            Console.WriteLine()
        End If

        Console.WriteLine("Health: {0} - {1}: {2}", csSheet.Health, csSheet.PowerType, csSheet.Power)
        Console.WriteLine()

        Console.WriteLine("Achievements: {0} - {1}/{2}", csSheet.AchievementPoints, csSheet.AchievementProgress.Earned, csSheet.AchievementProgress.Total)
        For Each aAchievements As CharacterSheet.Achievements In csSheet.AchievementCategories
            Console.WriteLine("  {0}: {1} - {2}/{3}", aAchievements.Name, aAchievements.Points, aAchievements.Earned, aAchievements.Total)
        Next
        Console.WriteLine()

        Console.WriteLine("Strength: {0} ({1} + {2}) Increases Attack Power by {3}", csSheet.Stats.Strength.Effective, csSheet.Stats.Strength.Base, csSheet.Stats.Strength.Effective - csSheet.Stats.Strength.Base, csSheet.Stats.Strength.AttackPower)
        Console.WriteLine("Agility: {0} ({1} + {2}) Increases Critical Hit chance by {3:P2}, Increases Armor by {4}", csSheet.Stats.Agility.Effective, csSheet.Stats.Agility.Base, csSheet.Stats.Agility.Effective - csSheet.Stats.Agility.Base, csSheet.Stats.Agility.CritHitPercent / 100, csSheet.Stats.Agility.Armor)
        Console.WriteLine("Stamina: {0} ({1} + {2}) Increases Health by {3}", csSheet.Stats.Stamina.Effective, csSheet.Stats.Stamina.Base, csSheet.Stats.Stamina.Effective - csSheet.Stats.Stamina.Base, csSheet.Stats.Stamina.Health)
        Console.WriteLine("Intellect: {0} ({1} + {2}) Increase Mana by {3}, Increases Spell Critical Hit by {4:P}", csSheet.Stats.Intellect.Effective, csSheet.Stats.Intellect.Base, csSheet.Stats.Intellect.Effective - csSheet.Stats.Intellect.Base, csSheet.Stats.Intellect.Mana, csSheet.Stats.Intellect.CritHitPercent / 100)
        Console.WriteLine("Spirit: {0} ({1} + {2}) Increases Health Regeneration by {3} Per Second while not in combat, Increases Mana Regeneration by {4} Per 5 Seconds while not casting", csSheet.Stats.Spirit.Effective, csSheet.Stats.Spirit.Base, csSheet.Stats.Spirit.Effective - csSheet.Stats.Spirit.Base, csSheet.Stats.Spirit.HealthRegen, csSheet.Stats.Spirit.ManaRegen)
        Console.WriteLine("Armor: {0} Reduces Physical Damage taken by {1:P2}", csSheet.Stats.Armor.Effective, csSheet.Stats.Armor.PercentDamageReduction / 100)
        Console.WriteLine()

        Console.WriteLine("Main Hand Damage: {0}-{1} - Damage per Second: {2:N1}", csSheet.Melee.MainHand.Min, csSheet.Melee.MainHand.Max, csSheet.Melee.MainHand.DPS)
        Console.WriteLine("Off Hand Damage: {0}-{1} - Damage per Second: {2:N1}", csSheet.Melee.OffHand.Min, csSheet.Melee.OffHand.Max, csSheet.Melee.OffHand.DPS)
        Console.WriteLine("Attack Speed: {0:N2} - Haste rating {1} ({2:P2} haste)", csSheet.Melee.MainHand.Speed, csSheet.Melee.MainHand.HasteRating, csSheet.Melee.MainHand.HastePercent / 100)
        Console.WriteLine("Melee Attack Power: {0} ({1} + {2}) Increases damage with melee weapons by {3:N1} damage per second", csSheet.Melee.AttackPower.Effective, csSheet.Melee.AttackPower.Base, csSheet.Melee.AttackPower.Effective - csSheet.Melee.AttackPower.Base, csSheet.Melee.AttackPower.IncreasedDPS)
        Console.WriteLine("Hit rating: {0} Increases your melee chance to hit a target of level {1} by {2:P2}, Armor penetration rating {3} (Enemy armor reduced by up to {4:P2})", csSheet.Melee.HitRating.Value, csSheet.Level, csSheet.Melee.HitRating.IncreasedHitPercent / 100, csSheet.Melee.HitRating.ArmorPenetrationRating, csSheet.Melee.HitRating.ArmorPenetrationPercent / 100)
        Console.WriteLine("Crit chance: {0:P2} Crit rating {1} (+{2:P2} crit chance)", csSheet.Melee.CritChance.Percent / 100, csSheet.Melee.CritChance.Rating, csSheet.Melee.CritChance.PlusPercent / 100)
        Console.WriteLine("Expertise: {0} Reduces chance to be dodged or parried by {1:P2}, Expertise rating {2} (+{3} expertise)", csSheet.Melee.Expertise.Value, csSheet.Melee.Expertise.Percent / 100, csSheet.Melee.Expertise.Rating, csSheet.Melee.Expertise.Additional)
        Console.WriteLine()

        Console.WriteLine("Ranged Damage: {0}-{1} - Damage per Second: {2:N1}", csSheet.Ranged.Weapon.Min, csSheet.Ranged.Weapon.Max, csSheet.Ranged.Weapon.DPS)
        Console.WriteLine("Attack Speed: {0:N2} - Haste rating {1} ({2:P2} haste)", csSheet.Ranged.Weapon.Speed, csSheet.Ranged.Weapon.HasteRating, csSheet.Ranged.Weapon.HastePercent / 100)
        Console.WriteLine("Ranged Attack Power: {0} ({1} + {2}) Increases damage with ranged weapons by {3:N1} damage per second", csSheet.Ranged.AttackPower.Effective, csSheet.Ranged.AttackPower.Base, csSheet.Ranged.AttackPower.Effective - csSheet.Ranged.AttackPower.Base, csSheet.Ranged.AttackPower.IncreasedDPS)
        Console.WriteLine("Hit rating: {0} Increases your ranged chance to hit a target of level {1} by {2:P2}, Armor penetration rating {3} (Enemy armor reduced by up to {4:P2})", csSheet.Ranged.HitRating.Value, csSheet.Level, csSheet.Ranged.HitRating.IncreasedHitPercent / 100, csSheet.Ranged.HitRating.ArmorPenetrationRating, csSheet.Ranged.HitRating.ArmorPenetrationPercent / 100)
        Console.WriteLine("Crit chance: {0:P2} Crit rating {1} (+{2:P2} crit chance)", csSheet.Ranged.CritChance.Percent / 100, csSheet.Ranged.CritChance.Rating, csSheet.Ranged.CritChance.PlusPercent / 100)
        Console.WriteLine()

        Console.WriteLine("Bonus Spell Damage - Holy {0} - Fire {1} - Nature {2} - Frost {3} - Shadow {4} - Arcane {5}", csSheet.Spell.SpellPower.Holy, csSheet.Spell.SpellPower.Fire, csSheet.Spell.SpellPower.Nature, csSheet.Spell.SpellPower.Frost, csSheet.Spell.SpellPower.Shadow, csSheet.Spell.SpellPower.Arcane)
        Console.WriteLine("Bonus Healing: {0}", csSheet.Spell.SpellPower.Healing)
        Console.WriteLine("Hit rating: {0} Increases your spell chance to hit a target of level {1} by {2:P2}, Spell Penetration {3} (Reduces enemy resistances by {4})", csSheet.Spell.HitRating.Value, csSheet.Level, csSheet.Spell.HitRating.IncreasedHitPercent / 100, csSheet.Spell.HitRating.Penetration, csSheet.Spell.HitRating.ReducedResistance)
        Console.WriteLine("Crit Rating: {0} - Holy {1:P2} - Fire {2:P2} - Nature {3:P2} - Frost {4:P2} - Shadow {5:P2} - Arcane {6:P2}", csSheet.Spell.CritChance.Rating, csSheet.Spell.CritChance.Holy / 100, csSheet.Spell.CritChance.Fire / 100, csSheet.Spell.CritChance.Nature / 100, csSheet.Spell.CritChance.Frost / 100, csSheet.Spell.CritChance.Shadow / 100, csSheet.Spell.CritChance.Arcane / 100)
        Console.WriteLine("Haste Rating: {0} Increases the speed that your spells cast by {1:P2}", csSheet.Spell.HasteRating, csSheet.Spell.HastePercent / 100)
        Console.WriteLine("Mana Regen: {0} mana regenerated every 5 seconds while not casting, {1} mana regenerated every 5 seconds while casting", csSheet.Spell.ManaRegenWhileNotCasting, csSheet.Spell.ManaRegenWhileCasting)
        Console.WriteLine()

        Console.WriteLine("Armor: {0} Reduces Physical Damage taken by {1:P2}", csSheet.Stats.Armor.Effective, csSheet.Stats.Armor.PercentDamageReduction / 100)
        Console.WriteLine("Defense: {0} Defense Rating {1} (+{2}), Increases chance to Dodge, Block and Parry by {3:P2}, Decreases chance to be hit and critically hit by {4:P2}", csSheet.Defense.Defense.Value, csSheet.Defense.Defense.Rating, csSheet.Defense.Defense.PlusDefense, csSheet.Defense.Defense.DecreasePercent / 100, csSheet.Defense.Defense.IncreasePercent / 100)
        Console.WriteLine("Dodge: {0:P2} - Dodge Rating: {1} Increases your chance to Dodge by {2:P2}", csSheet.Defense.Dodge.Percent / 100, csSheet.Defense.Dodge.Rating, csSheet.Defense.Dodge.IncreasePercent / 100)
        Console.WriteLine("Parry: {0:P2} - Parry Rating: {1} Increases your chance to Parry by {2:P2}", csSheet.Defense.Parry.Percent / 100, csSheet.Defense.Parry.Rating, csSheet.Defense.Parry.IncreasePercent / 100)
        Console.WriteLine("Block: {0:P2} - Block Rating: {1} Increases your chance to Block by {2:P2}", csSheet.Defense.Block.Percent / 100, csSheet.Defense.Block.Rating, csSheet.Defense.Block.IncreasePercent / 100)
        Console.WriteLine("Resilience: {0} - Reduces periodic damage and chance to be critically hit by {1:P2}, Reduces the effect of mana-drains and the damage of critical strikes by {2:P2}", csSheet.Defense.Resilience.Value, csSheet.Defense.Resilience.HitPercent / 100, csSheet.Defense.Resilience.DamagePercent / 100)
        Console.WriteLine()

        Console.WriteLine("Lifetime honorable kills: {0}", csSheet.LifetimeHonorKills)
        Console.WriteLine()

        For Each atTeam As CharacterSheet.ArenaTeam In csSheet.ArenaTeams
            Console.WriteLine("{0}v{0} arena team - {1}", atTeam.Size, atTeam.Name)
            Console.WriteLine("{0} rating - ranked {1} - {2} wins, {3} losses", atTeam.Rating, atTeam.Ranking, atTeam.SeasonGamesWon, atTeam.SeasonGamesPlayed - atTeam.SeasonGamesWon)
            For Each mMember As CharacterSheet.ArenaTeam.Member In atTeam.Members
                Console.WriteLine("  {0} - {1}-{2} - {3} rating", mMember.Name, mMember.SeasonGamesWon, mMember.SeasonGamesPlayed - mMember.SeasonGamesWon, mMember.PersonalRating)
            Next
            Console.WriteLine()
        Next

        Console.WriteLine("Press any key to continue.")
        Console.ReadKey(True)
    End Sub

    Private Sub CharacterStatisticsDemo()
        Console.Clear()
        Console.WriteLine("Character Statistics Demo")
        Console.WriteLine()

        Dim strCharacter As String
        Dim strRealm As String

        ' First, get the character
        Do
            Console.WriteLine("Please enter the name of the character whose statistics you wish to retrieve.")
            Console.Write(">")
            strCharacter = Console.ReadLine()

            If String.IsNullOrEmpty(strCharacter) Then
                Console.WriteLine("You must enter a character name.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        ' Next, get the realm
        Do
            Console.WriteLine("Please enter the name of the character's realm.")
            Console.Write(">")
            strRealm = Console.ReadLine()

            If String.IsNullOrEmpty(strRealm) Then
                Console.WriteLine("You must enter a realm.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        Dim csStatistics As New CharacterStatistics(strRealm, strCharacter)

        ' Display the statistics
        Do
            Console.Clear()
            Console.WriteLine("Statistics for {0}-{1}", strRealm, strCharacter)

            If csStatistics.RecentStatistics.Count > 0 Then
                Console.WriteLine()
                Console.WriteLine("Most recent statistics:")
                For Each sStatistic As Statistic In csStatistics.RecentStatistics
                    Console.WriteLine("{0} - {1}", sStatistic.Name, sStatistic.Quantity)
                Next
            End If

            Console.WriteLine()
            Console.WriteLine("Select a category")
            Console.WriteLine("  or press enter to exit")
            For Each cCategory As CharacterStatistics.Category In csStatistics.Categories
                Console.WriteLine("{0}) {1}", csStatistics.Categories.IndexOf(cCategory), cCategory.Name)
            Next

            Console.Write(">")
            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Exit Do
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse < csStatistics.Categories.Count Then
                    Console.Clear()
                    StatisticCategoryDetail(csStatistics.Categories(intResponse), csStatistics.CategoryStatistics(csStatistics.Categories(intResponse)).Statistics)
                    Console.WriteLine()
                    Console.WriteLine("Press any key to continue.")
                    Console.ReadKey(True)
                End If
            End If
        Loop
    End Sub

    Private Sub StatisticCategoryDetail(ByRef cCategory As CharacterStatistics.Category, ByRef cscCategory As CharacterStatisticsCategory.Category)
        Console.WriteLine("{0} statistics", cCategory.Name)
        Console.WriteLine()
        For Each sStatistic As Statistic In cscCategory.Statistics
            StatisticDetail(sStatistic)
        Next
        For Each cSubcategory As CharacterStatisticsCategory.Category In cscCategory.Subcategories
            StatisticSubcategoryDetail(cCategory.Subcategories(cscCategory.Subcategories.IndexOf(cSubcategory)), cSubcategory)
        Next
    End Sub

    Private Sub StatisticSubcategoryDetail(ByRef sCategory As CharacterStatistics.Subcategory, ByRef cscCategory As CharacterStatisticsCategory.Category)
        Console.WriteLine()
        Console.WriteLine("{0} statistics", sCategory.Name)
        Console.WriteLine()
        For Each sStatistic As Statistic In cscCategory.Statistics
            StatisticDetail(sStatistic)
        Next
    End Sub

    Private Sub StatisticDetail(ByRef sStatistic As Statistic)
        If String.IsNullOrEmpty(sStatistic.Highest) Then
            Console.WriteLine("{0} - {1}", sStatistic.Name, sStatistic.Quantity)
        Else
            Console.WriteLine("{0} - {1} ({2})", sStatistic.Name, sStatistic.Highest, sStatistic.Quantity)
        End If
    End Sub

    Private Sub CharacterTalentsDemo()
        Console.Clear()
        Console.WriteLine("Character Talents Demo")
        Console.WriteLine()

        Dim strCharacter As String
        Dim strRealm As String

        ' First, get the character
        Do
            Console.WriteLine("Please enter the name of the character whose talents you wish to retrieve.")
            Console.Write(">")
            strCharacter = Console.ReadLine()

            If String.IsNullOrEmpty(strCharacter) Then
                Console.WriteLine("You must enter a character name.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        ' Next, get the realm
        Do
            Console.WriteLine("Please enter the name of the character's realm.")
            Console.Write(">")
            strRealm = Console.ReadLine()

            If String.IsNullOrEmpty(strRealm) Then
                Console.WriteLine("You must enter a realm.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        ' Do the lookup
        Dim ctTalents As New CharacterTalents(strRealm, strCharacter)

        ' Display the talents
        Console.Clear()
        Console.WriteLine("Character Talents for {0}-{1}", strRealm, strCharacter)
        Console.WriteLine()

        Console.WriteLine("Primary Talents")
        For Each tTree As TalentTree.TalentTree In ctTalents.PrimaryTalents.TalentTrees
            Console.WriteLine("  {0}", tTree.Name)
            For Each tTalent As TalentTree.Talent In tTree.Talents
                Console.WriteLine("    {0} - {1}/{2}", tTalent.Name, tTalent.Points, tTalent.MaxPoints)
                If tTalent.Points > 0 Then
                    Console.WriteLine("      {0}", tTalent.Ranks(tTalent.Points - 1))
                    If tTalent.SpellCastTime > 0 Then
                        Console.WriteLine("        {0:N2} second cast", tTalent.SpellCastTime)
                    End If
                    If tTalent.SpellCooldown > 0 Then
                        Console.WriteLine("        {0:N2} second cooldown", tTalent.SpellCooldown / 1000)
                    End If
                    If tTalent.SpellMaxRange > 0 Then
                        Console.WriteLine("        {0} yard range", tTalent.SpellMaxRange)
                    End If
                    For Each pPower As TalentTree.Power In tTalent.RequiredPower
                        Select Case pPower.Type
                            Case "mana"
                                Console.WriteLine("          Requires {0} percent of base mana", pPower.Cost)
                            Case "energy"
                                Console.WriteLine("          Requires {0} energy", pPower.Cost)
                            Case "rage"
                                Console.WriteLine("          Requires {0} rage", pPower.Cost)
                            Case "runic"
                                Console.WriteLine("          Requires {0} runic power", pPower.Cost)
                            Case "blood"
                                Console.WriteLine("          Requires {0} blood rune{1}", pPower.Cost, IIf(pPower.Cost > 1, "s", ""))
                            Case "frost"
                                Console.WriteLine("          Requires {0} frost rune{1}", pPower.Cost, IIf(pPower.Cost > 1, "s", ""))
                            Case "unholy"
                                Console.WriteLine("          Requires {0} unholy rune{1}", pPower.Cost, IIf(pPower.Cost > 1, "s", ""))
                        End Select
                    Next
                End If
            Next
            Console.WriteLine()
        Next

        Console.WriteLine("Primary Glyphs")
        For Each gGlyph As CharacterTalents.Glyph In ctTalents.PrimaryGlyphs
            Console.WriteLine("  {0} - {1} - {2}", gGlyph.Type, gGlyph.Name, gGlyph.Effect)
        Next
        Console.WriteLine()

        If ctTalents.SecondaryTalents IsNot Nothing Then
            Console.WriteLine("Secondary Talents")
            For Each tTree As TalentTree.TalentTree In ctTalents.SecondaryTalents.TalentTrees
                Console.WriteLine("  {0}", tTree.Name)
                For Each tTalent As TalentTree.Talent In tTree.Talents
                    Console.WriteLine("    {0} - {1}/{2}", tTalent.Name, tTalent.Points, tTalent.MaxPoints)
                    If tTalent.Points > 0 Then
                        Console.WriteLine("      {0}", tTalent.Ranks(tTalent.Points - 1))
                        If tTalent.SpellCastTime > 0 Then
                            Console.WriteLine("        {0:N2} second cast", tTalent.SpellCastTime)
                        End If
                        If tTalent.SpellCooldown > 0 Then
                            Console.WriteLine("        {0:N2} second cooldown", tTalent.SpellCooldown / 1000)
                        End If
                        If tTalent.SpellMaxRange > 0 Then
                            Console.WriteLine("        {0} yard range", tTalent.SpellMaxRange)
                        End If
                        For Each pPower As TalentTree.Power In tTalent.RequiredPower
                            Select Case pPower.Type
                                Case "mana"
                                    Console.WriteLine("          Requires {0} percent of base mana", pPower.Cost)
                                Case "energy"
                                    Console.WriteLine("          Requires {0} energy", pPower.Cost)
                                Case "rage"
                                    Console.WriteLine("          Requires {0} rage", pPower.Cost)
                                Case "runic"
                                    Console.WriteLine("          Requires {0} runic power", pPower.Cost)
                                Case "blood"
                                    Console.WriteLine("          Requires {0} blood rune{1}", pPower.Cost, IIf(pPower.Cost > 1, "s", ""))
                                Case "frost"
                                    Console.WriteLine("          Requires {0} frost rune{1}", pPower.Cost, IIf(pPower.Cost > 1, "s", ""))
                                Case "unholy"
                                    Console.WriteLine("          Requires {0} unholy rune{1}", pPower.Cost, IIf(pPower.Cost > 1, "s", ""))
                            End Select
                        Next
                    End If
                Next
                Console.WriteLine()
            Next

            Console.WriteLine("Secondary Glyphs")
            For Each gGlyph As CharacterTalents.Glyph In ctTalents.SecondaryGlyphs
                Console.WriteLine("  {0} - {1} - {2}", gGlyph.Type, gGlyph.Name, gGlyph.Effect)
            Next
            Console.WriteLine()
        End If

        For Each pPet As CharacterTalents.Pet In ctTalents.Pets
            Console.WriteLine("Talents for pet {0}, Level {1} {2} ({3})", pPet.Name, pPet.Level, pPet.Family, pPet.NPCName)
            Console.WriteLine("  {0}", pPet.Talents.Name)
            For Each tTalent As TalentTree.Talent In pPet.Talents.Talents
                Console.WriteLine("    {0} - {1}/{2}", tTalent.Name, tTalent.Points, tTalent.MaxPoints)
                If tTalent.Points > 0 Then
                    Console.WriteLine("      {0}", tTalent.Ranks(tTalent.Points - 1))
                    If tTalent.SpellCastTime > 0 Then
                        Console.WriteLine("        {0:N2} second cast", tTalent.SpellCastTime)
                    End If
                    If tTalent.SpellCooldown > 0 Then
                        Console.WriteLine("        {0:N2} second cooldown", tTalent.SpellCooldown / 1000)
                    End If
                    If tTalent.SpellMaxRange > 0 Then
                        Console.WriteLine("        {0} yard range", tTalent.SpellMaxRange)
                    End If
                    For Each pPower As TalentTree.Power In tTalent.RequiredPower
                        Select Case pPower.Type
                            Case "mana"
                                Console.WriteLine("          Requires {0} percent of base mana", pPower.Cost)
                            Case "energy"
                                Console.WriteLine("          Requires {0} energy", pPower.Cost)
                            Case "rage"
                                Console.WriteLine("          Requires {0} rage", pPower.Cost)
                            Case "runic"
                                Console.WriteLine("          Requires {0} runic power", pPower.Cost)
                            Case "blood"
                                Console.WriteLine("          Requires {0} blood rune{1}", pPower.Cost, IIf(pPower.Cost > 1, "s", ""))
                            Case "frost"
                                Console.WriteLine("          Requires {0} frost rune{1}", pPower.Cost, IIf(pPower.Cost > 1, "s", ""))
                            Case "unholy"
                                Console.WriteLine("          Requires {0} unholy rune{1}", pPower.Cost, IIf(pPower.Cost > 1, "s", ""))
                        End Select
                    Next
                End If
            Next
            Console.WriteLine()
        Next

        Console.WriteLine("Press any key to continue.")
        Console.ReadKey(True)
    End Sub

    Private Sub DungeonDemo()
        Console.Clear()
        Console.WriteLine("Dungeon Data Demo")
        Console.WriteLine()

        Dim dDungeons As New Dungeons()

        For Each dDungeon As Dungeons.Dungeon In dDungeons.Dungeons
            Console.WriteLine("{0} ({1}-{2}, {3}-man {4}) - {5} - {6}", dDungeon.Name, dDungeon.LevelMin, dDungeon.LevelMax, dDungeon.PartySize, If(dDungeon.Raid, "raid", "dungeon"), If(dDungeon.HasHeroic, "Heroic available", "No heroic available"), [Enum].GetName(GetType(Enums.ReleaseType), CType(dDungeon.Release, ReleaseType)))
            For Each bBoss As Dungeons.Boss In dDungeon.Bosses
                Console.WriteLine("  {0}", bBoss.Name)
            Next
            Console.WriteLine()
        Next

        Console.WriteLine("Press any key to continue.")
        Console.ReadKey(True)
    End Sub

    Private Sub FactionsDemo()
        Console.Clear()
        Console.WriteLine("Factions Demo")
        Console.WriteLine()

        Dim fFactions As New Factions()

        For Each fFaction As Factions.Faction In fFactions.Factions
            Console.WriteLine("{0} - {1}", fFaction.Name, [Enum].GetName(GetType(Enums.ReleaseType), CType(fFaction.Release, ReleaseType)))
        Next

        Console.WriteLine()
        Console.WriteLine("Press any key to continue.")
        Console.ReadKey(True)
    End Sub

    Private Sub ItemInfoDemo()
        Console.Clear()
        Console.WriteLine("Item Info Demo")
        Console.WriteLine()

        Dim intItemID As Integer

        ' Get the item number
        Do
            Console.WriteLine("Please enter the ID number of the item you wish to lookup.")
            Console.Write(">")
            Dim strItemID As Integer = Console.ReadLine()

            If String.IsNullOrEmpty(strItemID) Then
                Console.WriteLine("You must enter an item number.")
                Console.WriteLine()
            ElseIf Not Integer.TryParse(strItemID, intItemID) Then
                Console.WriteLine("You must enter an item number.")
                Console.WriteLine()
            Else
                Exit Do
            End If
        Loop

        Dim iiItemInfo As New ItemInfo(intItemID)

        ' Display the item's information
        Console.Clear()
        Console.WriteLine("{0} - {1} iLevel {2} - {3}", iiItemInfo.Name, [Enum].GetName(GetType(Enums.RarityType), iiItemInfo.Quality), iiItemInfo.Level, iiItemInfo.Type)
        If iiItemInfo.FactionRestriction <> FactionType.None Then
            Console.WriteLine("Restricted to {0}", iiItemInfo.FactionRestriction)
            Console.WriteLine("Equivalent items:")
            For Each tfiItem As ItemInfo.TranslationForItem In iiItemInfo.TranslationFor
                Console.WriteLine("  {0}: {1} - {2}", tfiItem.Faction, tfiItem.ID, tfiItem.Name)
            Next
        End If
        Console.WriteLine()

        If iiItemInfo.RandomProperties.Count > 0 Then
            Console.WriteLine("Random Enchantment Properties:")
            For Each rpProperty As ItemInfo.RandomProperty In iiItemInfo.RandomProperties
                Console.WriteLine("  {0} - {1}", rpProperty.Suffix, rpProperty.Enchantments)
            Next
            Console.WriteLine()
        End If

        If Not String.IsNullOrEmpty(iiItemInfo.RequiredAbility) Then
            Console.WriteLine("Required ability: {0}", iiItemInfo.RequiredAbility)
            Console.WriteLine()
        End If

        If Not String.IsNullOrEmpty(iiItemInfo.RequiredSkill) Then
            Console.WriteLine("Required skill: {0} ({1})", iiItemInfo.RequiredSkill, iiItemInfo.RequiredSkillRank)
            Console.WriteLine()
        End If

        If iiItemInfo.Cost IsNot Nothing Then
            Console.WriteLine("Costs:")
            If iiItemInfo.Cost.Faction <> FactionType.None Then
                Console.WriteLine("  Only purchasable by {0}", [Enum].GetName(GetType(Enums.FactionType), iiItemInfo.Cost.Faction))
            End If
            If iiItemInfo.Cost.BuyPrice > 0 Then
                Console.WriteLine("  Buy price: {0}g {1}s {2}c", Math.Floor(iiItemInfo.Cost.BuyPrice / 10000), Math.Floor(iiItemInfo.Cost.BuyPrice / 100) Mod 100, iiItemInfo.Cost.BuyPrice Mod 100)
            End If
            If iiItemInfo.Cost.SellPrice > 0 Then
                Console.WriteLine("  Sell price: {0}g {1}s {2}c", Math.Floor(iiItemInfo.Cost.SellPrice / 10000), Math.Floor(iiItemInfo.Cost.SellPrice / 100) Mod 100, iiItemInfo.Cost.SellPrice Mod 100)
            End If
            If iiItemInfo.Cost.Arena > 0 Then
                Console.WriteLine("  {0} arena points", iiItemInfo.Cost.Arena)
            End If
            If iiItemInfo.Cost.Honor > 0 Then
                Console.WriteLine("  {0} honor points", iiItemInfo.Cost.Honor)
            End If
            For Each tToken As ItemInfo.ItemCost.TokenCost In iiItemInfo.Cost.Token
                Console.WriteLine("  {0} {1}", tToken.Count, tToken.Item)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.CurrencyFor.Count > 0 Then
            Console.WriteLine("Currency for:")
            For Each ciItem As ItemInfo.CurrencyItem In iiItemInfo.CurrencyFor
                Console.WriteLine("  {0}", ciItem.Name)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.Vendors.Count > 0 Then
            Console.WriteLine("Vendors bought from:")
            For Each cVendor As ItemInfo.Creature In iiItemInfo.Vendors
                Console.WriteLine("  {0} - {1}", cVendor.Name, cVendor.Area)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.StartsQuest IsNot Nothing Then
            Console.WriteLine("Starts quest: {0} - {1}", iiItemInfo.StartsQuest.Name, iiItemInfo.StartsQuest.Area)
            Console.WriteLine()
        End If

        If iiItemInfo.ProvidedForQuests.Count > 0 Then
            Console.WriteLine("Provided for quests:")
            For Each qQuest As ItemInfo.Quest In iiItemInfo.ProvidedForQuests
                Console.WriteLine("  {0} - {1}", qQuest.Name, qQuest.Area)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.ObjectiveOfQuests.Count > 0 Then
            Console.WriteLine("Objective of quests:")
            For Each qQuest As ItemInfo.Quest In iiItemInfo.ObjectiveOfQuests
                Console.WriteLine("  {0} - {1}", qQuest.Name, qQuest.Area)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.RewardFromQuests.Count > 0 Then
            Console.WriteLine("Reward from quests:")
            For Each qQuest As ItemInfo.Quest In iiItemInfo.RewardFromQuests
                Console.WriteLine("  {0} - {1}", qQuest.Name, qQuest.Area)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.MultiLoot Or iiItemInfo.MultiLootQuest Then
            Console.WriteLine("This item will drop for everyone in the party.")
            Console.WriteLine()
        End If

        If iiItemInfo.CreatedBy IsNot Nothing Then
            Console.WriteLine("Created by {0}", iiItemInfo.CreatedBy.Name)
            For Each rReagent As ItemInfo.Reagent In iiItemInfo.CreatedBy.Reagents
                Console.WriteLine("  {0}x {1}", rReagent.Count, rReagent.Name)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.ReagentFor.Count > 0 Then
            Console.WriteLine("Reagent for:")
            For Each siSpell As ItemInfo.SpellItem In iiItemInfo.ReagentFor
                Console.WriteLine("  {0}", siSpell.Name)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.DisenchantLoot.Count > 0 Then
            Console.WriteLine("Disenchant information:")
            Console.WriteLine("  Requires Enchanting ({0})", iiItemInfo.DisenchantLootSkillRank)
            For Each diItem As ItemInfo.DisenchantItem In iiItemInfo.DisenchantLoot
                Console.WriteLine("  {0} - {1}", diItem.Name, [Enum].GetName(GetType(Enums.DropRateType), diItem.DropRate))
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.ContainerObjects.Count > 0 Then
            Console.WriteLine("Found in:")
            For Each oObject As ItemInfo.Object In iiItemInfo.ContainerObjects
                Console.WriteLine("  {0} - {1} - {2}", oObject.Name, oObject.Area, [Enum].GetName(GetType(Enums.DropRateType), oObject.DropRate))
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.DropGeneralCreatures IsNot Nothing Then
            Console.WriteLine("Drops in:")
            For Each aiArea As ItemInfo.CreatureInfo.AreaInfo In iiItemInfo.DropGeneralCreatures.Area
                Console.WriteLine("  {0}", aiArea.Name)
            Next
            Console.WriteLine("Drops from:")
            For Each ciCreature As ItemInfo.CreatureInfo.CreatureType In iiItemInfo.DropGeneralCreatures.Type
                Console.WriteLine("  {0}", ciCreature.Name)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.DropSpecificCreatures.Count > 0 Then
            Console.WriteLine("Drops from:")
            For Each cCreature As ItemInfo.Creature In iiItemInfo.DropSpecificCreatures
                Console.WriteLine("  {0} - {1}", cCreature.Name, cCreature.Area)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.HerbGeneralCreatures IsNot Nothing Then
            Console.WriteLine("Herbed in:")
            For Each aiArea As ItemInfo.CreatureInfo.AreaInfo In iiItemInfo.HerbGeneralCreatures.Area
                Console.WriteLine("  {0}", aiArea.Name)
            Next
            Console.WriteLine("Herbed from:")
            For Each ciCreature As ItemInfo.CreatureInfo.CreatureType In iiItemInfo.HerbGeneralCreatures.Type
                Console.WriteLine("  {0}", ciCreature.Name)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.HerbSpecificCreatures.Count > 0 Then
            Console.WriteLine("Herbed from:")
            For Each cCreature As ItemInfo.Creature In iiItemInfo.HerbSpecificCreatures
                Console.WriteLine("  {0} - {1}", cCreature.Name, cCreature.Area)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.MineGeneralCreatures IsNot Nothing Then
            Console.WriteLine("Mined in:")
            For Each aiArea As ItemInfo.CreatureInfo.AreaInfo In iiItemInfo.MineGeneralCreatures.Area
                Console.WriteLine("  {0}", aiArea.Name)
            Next
            Console.WriteLine("Mined from:")
            For Each ciCreature As ItemInfo.CreatureInfo.CreatureType In iiItemInfo.MineGeneralCreatures.Type
                Console.WriteLine("  {0}", ciCreature.Name)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.MineSpecificCreatures.Count > 0 Then
            Console.WriteLine("Mined from:")
            For Each cCreature As ItemInfo.Creature In iiItemInfo.MineSpecificCreatures
                Console.WriteLine("  {0} - {1}", cCreature.Name, cCreature.Area)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.PickPocketGeneralCreatures IsNot Nothing Then
            Console.WriteLine("Pick pocketed in:")
            For Each aiArea As ItemInfo.CreatureInfo.AreaInfo In iiItemInfo.PickPocketGeneralCreatures.Area
                Console.WriteLine("  {0}", aiArea.Name)
            Next
            Console.WriteLine("Pick pocketed from:")
            For Each ciCreature As ItemInfo.CreatureInfo.CreatureType In iiItemInfo.PickPocketGeneralCreatures.Type
                Console.WriteLine("  {0}", ciCreature.Name)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.PickPocketSpecificCreatures.Count > 0 Then
            Console.WriteLine("Pick pocketed from:")
            For Each cCreature As ItemInfo.Creature In iiItemInfo.PickPocketSpecificCreatures
                Console.WriteLine("  {0} - {1}", cCreature.Name, cCreature.Area)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.SkinGeneralCreatures IsNot Nothing Then
            Console.WriteLine("Skined in:")
            For Each aiArea As ItemInfo.CreatureInfo.AreaInfo In iiItemInfo.SkinGeneralCreatures.Area
                Console.WriteLine("  {0}", aiArea.Name)
            Next
            Console.WriteLine("Skined from:")
            For Each ciCreature As ItemInfo.CreatureInfo.CreatureType In iiItemInfo.SkinGeneralCreatures.Type
                Console.WriteLine("  {0}", ciCreature.Name)
            Next
            Console.WriteLine()
        End If

        If iiItemInfo.SkinSpecificCreatures.Count > 0 Then
            Console.WriteLine("Skined from:")
            For Each cCreature As ItemInfo.Creature In iiItemInfo.SkinSpecificCreatures
                Console.WriteLine("  {0} - {1}", cCreature.Name, cCreature.Area)
            Next
            Console.WriteLine()
        End If

        Console.WriteLine("Press any key to continue.")
        Console.ReadKey(True)
    End Sub

    Private Sub ItemSearchDemo()
        Dim qfQuery As New ItemSearch.QueryFilter

        Dim dDungeons As New Dungeons()
        Dim fFactions As New Factions()

        Console.Clear()
        Console.WriteLine("Item Search Demo")
        Console.WriteLine()

        ' Set the parameters for the search
        Do
            Console.WriteLine("Select an option below to modify the filter.")
            Console.WriteLine("1) Source: {0}", [Enum].GetName(GetType(Enums.SourceType), qfQuery.Source.Source))
            Select Case qfQuery.Source.Source
                Case SourceType.DungeonsAndRaidDrops
                    If (qfQuery.Source.DungeonType = DungeonType.AllDungeonsAndRaids And qfQuery.Source.Dungeon = "all") Or qfQuery.Source.DungeonType <> DungeonType.AllDungeonsAndRaids Then
                        Console.WriteLine("   Drops from: {0}", [Enum].GetName(GetType(Enums.DungeonType), qfQuery.Source.DungeonType))
                        Select Case qfQuery.Source.DungeonType
                            Case DungeonType.DungeonsOnly
                                Console.WriteLine("   Difficulty: {0}", [Enum].GetName(GetType(Enums.DifficultyType), qfQuery.Source.Difficulty))
                        End Select
                    Else
                        Dim dDungeon As Dungeons.Dungeon = dDungeons.Dungeons.Where(Function(d) d.Key = qfQuery.Source.Dungeon).First()
                        Console.WriteLine("   Drops from: {0}", dDungeon.Name)
                        If qfQuery.Source.Boss = 0 Then
                            Console.WriteLine("   Boss: All {0} Bosses", dDungeon.Name)
                        Else
                            Console.WriteLine("   Boss: {0}", dDungeon.Bosses.Where(Function(b) b.ID = qfQuery.Source.Boss).First().Name)
                        End If
                        If dDungeon.HasHeroic Then
                            Console.WriteLine("   Difficulty: {0}", [Enum].GetName(GetType(Enums.DifficultyType), qfQuery.Source.Difficulty))
                        End If
                    End If
                Case SourceType.PvpRewardsAlliance
                    Console.WriteLine("   PvP Source: {0}", [Enum].GetName(GetType(Enums.PvpAllianceSourceType), qfQuery.Source.PvpAllianceSource))
                Case SourceType.PvpRewardsHorde
                    Console.WriteLine("   PvP Source: {0}", [Enum].GetName(GetType(Enums.PvpHordeSourceType), qfQuery.Source.PvpHordeSource))
                Case SourceType.ReputationRewards
                    If qfQuery.Source.Faction = -1 Then
                        Console.WriteLine("   Faction: All Factions")
                    Else
                        Console.WriteLine("   Faction: {0}", fFactions.Factions.ToArray.Where(Function(f) f.ID = qfQuery.Source.Faction).First().Name)
                    End If
            End Select

            Console.WriteLine("2) Item Type: {0}", [Enum].GetName(GetType(Enums.ItemTypeType), qfQuery.ItemType.ItemType))
            Select Case qfQuery.ItemType.ItemType
                Case ItemTypeType.AllItems
                    Console.WriteLine("   Desired by: {0} - {1}", [Enum].GetName(GetType(Enums.DesiredByType), qfQuery.ItemType.DesiredBy), [Enum].GetName(GetType(Enums.DesiredByRoleType), qfQuery.ItemType.DesiredByRole))
                    Console.WriteLine("   Required level: {0} to {1}", qfQuery.ItemType.RequiredLevelMin, qfQuery.ItemType.RequiredLevelMax)
                    Console.WriteLine("   Rarity: {0}", [Enum].GetName(GetType(Enums.RarityType), qfQuery.ItemType.Rarity))
                Case ItemTypeType.Armor
                    Console.WriteLine("   Desired by: {0} - {1}", [Enum].GetName(GetType(Enums.DesiredByType), qfQuery.ItemType.DesiredBy), [Enum].GetName(GetType(Enums.DesiredByRoleType), qfQuery.ItemType.DesiredByRole))
                    Console.WriteLine("   Slot: {0}", [Enum].GetName(GetType(Enums.ArmorSlotType), qfQuery.ItemType.ArmorSlot))
                    Console.WriteLine("   Armor Type: {0}", [Enum].GetName(GetType(Enums.ArmorTypeType), qfQuery.ItemType.ArmorType))
                    Console.WriteLine("   Required level: {0} to {1}", qfQuery.ItemType.RequiredLevelMin, qfQuery.ItemType.RequiredLevelMax)
                    Console.WriteLine("   Rarity: {0}", [Enum].GetName(GetType(Enums.RarityType), qfQuery.ItemType.Rarity))
                Case ItemTypeType.Consumables
                    Console.WriteLine("   Rarity: {0}", [Enum].GetName(GetType(Enums.RarityType), qfQuery.ItemType.Rarity))
                Case ItemTypeType.Containers
                    Console.WriteLine("   Bag Type: {0}", [Enum].GetName(GetType(Enums.BagTypeType), qfQuery.ItemType.ContainerType))
                Case ItemTypeType.EnchantmentsPermanent
                    Console.WriteLine("   Slot: {0}", [Enum].GetName(GetType(Enums.PermanentEnchantmentSlotType), qfQuery.ItemType.PermanentEnchantmentSlot))
                    Console.WriteLine("   Rarity: {0}", [Enum].GetName(GetType(Enums.RarityType), qfQuery.ItemType.Rarity))
                Case ItemTypeType.EnchantmentsTemporary
                    Console.WriteLine("   Rarity: {0}", [Enum].GetName(GetType(Enums.RarityType), qfQuery.ItemType.Rarity))
                Case ItemTypeType.Gems
                    Console.WriteLine("   Desired by: {0} - {1}", [Enum].GetName(GetType(Enums.DesiredByType), qfQuery.ItemType.DesiredBy), [Enum].GetName(GetType(Enums.DesiredByRoleType), qfQuery.ItemType.DesiredByRole))
                    Console.WriteLine("   Gem Type: {0}", [Enum].GetName(GetType(Enums.GemTypeType), qfQuery.ItemType.GemType))
                    Console.WriteLine("   Rarity: {0}", [Enum].GetName(GetType(Enums.RarityType), qfQuery.ItemType.Rarity))
                Case ItemTypeType.Glyphs
                    Console.WriteLine("   Desired by: {0} - {1}", [Enum].GetName(GetType(Enums.DesiredByType), qfQuery.ItemType.DesiredBy), [Enum].GetName(GetType(Enums.DesiredByRoleType), qfQuery.ItemType.DesiredByRole))
                Case ItemTypeType.Miscellaneous
                    Console.WriteLine("   Rarity: {0}", [Enum].GetName(GetType(Enums.RarityType), qfQuery.ItemType.Rarity))
                Case ItemTypeType.Projectiles
                    Console.WriteLine("   Type: {0}", [Enum].GetName(GetType(Enums.ProjectileTypeType), qfQuery.ItemType.ProjectilesType))
                    Console.WriteLine("   Rarity: {0}", [Enum].GetName(GetType(Enums.RarityType), qfQuery.ItemType.Rarity))
                Case ItemTypeType.Quivers
                    Console.WriteLine("   Type: {0}", [Enum].GetName(GetType(Enums.QuiverTypeType), qfQuery.ItemType.QuiverType))
                Case ItemTypeType.Reagents
                    Console.WriteLine("   Rarity: {0}", [Enum].GetName(GetType(Enums.RarityType), qfQuery.ItemType.Rarity))
                Case ItemTypeType.Recipes
                    Console.WriteLine("   Recipes: {0}", [Enum].GetName(GetType(Enums.RecipesTypeType), qfQuery.ItemType.RecipesType))
                    Console.WriteLine("   Rarity: {0}", [Enum].GetName(GetType(Enums.RarityType), qfQuery.ItemType.Rarity))
                    Console.WriteLine("   Skill Level: {0} - {1}", qfQuery.ItemType.SkillLevelMin, qfQuery.ItemType.SkillLevelMax)
                Case ItemTypeType.TradeGoods
                    Console.WriteLine("   Rarity: {0}", [Enum].GetName(GetType(Enums.RarityType), qfQuery.ItemType.Rarity))
                Case ItemTypeType.Weapons
                    Console.WriteLine("   Desired by: {0} - {1}", [Enum].GetName(GetType(Enums.DesiredByType), qfQuery.ItemType.DesiredBy), [Enum].GetName(GetType(Enums.DesiredByRoleType), qfQuery.ItemType.DesiredByRole))
                    Console.WriteLine("   Slot: {0}", [Enum].GetName(GetType(Enums.WeaponSlotType), qfQuery.ItemType.WeaponSlot))
                    Console.WriteLine("   Weapon Type: {0}", [Enum].GetName(GetType(Enums.WeaponTypeType), qfQuery.ItemType.WeaponType))
                    Console.WriteLine("   Required level: {0} to {1}", qfQuery.ItemType.RequiredLevelMin, qfQuery.ItemType.RequiredLevelMax)
                    Console.WriteLine("   Rarity: {0}", [Enum].GetName(GetType(Enums.RarityType), qfQuery.ItemType.Rarity))
            End Select
            If qfQuery.AdvancedOptions.Count > 0 Then
                Console.WriteLine("   Advanced Filters:")
                For Each aofFilter As ItemSearch.QueryFilter.AdvancedOptionsFilter In qfQuery.AdvancedOptions
                    If aofFilter.AdvancedOptions <= Enums.AdvancedOptionsType.Weapon_Speed Then
                        Dim strOperator As String = ""
                        Select Case aofFilter.Operator
                            Case AdvancedOptionsOperatorType.EqualTo
                                strOperator = "="
                            Case AdvancedOptionsOperatorType.GreaterThan
                                strOperator = ">"
                            Case AdvancedOptionsOperatorType.GreaterThanEqualTo
                                strOperator = ">="
                            Case AdvancedOptionsOperatorType.LessThan
                                strOperator = "<"
                            Case AdvancedOptionsOperatorType.LessThanEqualTo
                                strOperator = "<="
                        End Select
                        Console.WriteLine("     {0} {1} {2}", [Enum].GetName(GetType(Enums.AdvancedOptionsType), aofFilter.AdvancedOptions), strOperator, aofFilter.Range)
                    Else
                        Console.WriteLine("     {0}", [Enum].GetName(GetType(Enums.AdvancedOptionsType), aofFilter.AdvancedOptions))
                    End If
                Next
            End If
            Console.WriteLine("3) Search Query: {0}", qfQuery.SearchQuery)
            Console.WriteLine()
            Console.WriteLine("4) Perform Search")
            Console.WriteLine()

            Console.Write(">")
            Dim strResponse As String = Console.ReadLine()
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 1 And intResponse <= 4 Then
                    Select Case intResponse
                        Case 1
                            Console.Clear()
                            Console.WriteLine("Source Selection")
                            Console.WriteLine()
                            Do
                                Console.WriteLine("Select a source:")
                                Console.WriteLine("0) All Sources")
                                Console.WriteLine("1) Dungeons and Raid Drops")
                                Console.WriteLine("2) Reputation Rewards")
                                Console.WriteLine("3) Quest Rewards")
                                Console.WriteLine("4) PvP Rewards - Alliance")
                                Console.WriteLine("5) PvP Rewards - Horde")
                                Console.WriteLine("6) Exit")
                                Console.WriteLine()

                                Console.Write(">")
                                Dim strResponse2 As String = Console.ReadLine()
                                Dim intResponse2 As Integer
                                If Integer.TryParse(strResponse2, intResponse2) Then
                                    If intResponse2 >= 0 And intResponse2 <= 6 Then
                                        Select Case intResponse2
                                            Case 0
                                                qfQuery.Source.Source = SourceType.AllSources
                                            Case 1
                                                qfQuery.Source.Source = SourceType.DungeonsAndRaidDrops
                                                Console.Clear()
                                                Console.WriteLine("Dungeon and Raid Selection")
                                                Console.WriteLine()
                                                Do
                                                    Console.WriteLine("Select a dungeon and raid source")
                                                    Console.WriteLine()
                                                    Console.WriteLine("0) All Dungeons and Raids")
                                                    Console.WriteLine("1) Dungeons Only")
                                                    Console.WriteLine("2) Raids Only")
                                                    Console.WriteLine("3) Badge of Justice Rewards")
                                                    Console.WriteLine("4) Emblem of Heroism Rewards")
                                                    Console.WriteLine("5) Emblem of Valor Rewards")
                                                    Console.WriteLine("6) Emblem of Conquest Rewards")
                                                    Console.WriteLine("7) Choose a specific dungeon")
                                                    Console.WriteLine("8) Exit")
                                                    Console.WriteLine()

                                                    Console.Write(">")
                                                    Dim strResponse3 As String = Console.ReadLine()
                                                    Dim intResponse3 As Integer
                                                    If Integer.TryParse(strResponse3, intResponse3) Then
                                                        If intResponse3 >= 0 And intResponse3 <= 8 Then
                                                            Select Case intResponse3
                                                                Case 0
                                                                    qfQuery.Source.DungeonType = DungeonType.AllDungeonsAndRaids
                                                                Case 1
                                                                    qfQuery.Source.DungeonType = DungeonType.DungeonsOnly
                                                                    qfQuery.Source.Difficulty = SelectDifficulty()
                                                                Case 2
                                                                    qfQuery.Source.DungeonType = DungeonType.RaidsOnly
                                                                Case 3
                                                                    qfQuery.Source.DungeonType = DungeonType.BadgeOfJusticeRewards
                                                                Case 4
                                                                    qfQuery.Source.DungeonType = DungeonType.EmblemOfHeroism
                                                                Case 5
                                                                    qfQuery.Source.DungeonType = DungeonType.EmblemOfValor
                                                                Case 6
                                                                    qfQuery.Source.DungeonType = DungeonType.EmblemOfConquest
                                                                Case 7
                                                                    qfQuery.Source.Dungeon = SelectDungeon(dDungeons)
                                                                    If qfQuery.Source.Dungeon <> "all" Then
                                                                        Dim dDungeon As Dungeons.Dungeon = dDungeons.Dungeons.Where(Function(d) d.Key = qfQuery.Source.Dungeon)
                                                                        qfQuery.Source.Boss = SelectBoss(dDungeon)
                                                                        If dDungeon.HasHeroic Then
                                                                            qfQuery.Source.Difficulty = SelectDifficulty()
                                                                        End If
                                                                    End If
                                                            End Select
                                                            Console.Clear()
                                                            Exit Do
                                                        End If
                                                    End If
                                                    Console.Clear()
                                                    Console.WriteLine("Invalid selection.  Please try again.")
                                                    Console.WriteLine()
                                                Loop
                                            Case 2
                                                qfQuery.Source.Source = SourceType.ReputationRewards
                                                qfQuery.Source.Faction = SelectFaction(fFactions)
                                            Case 3
                                                qfQuery.Source.Source = SourceType.QuestRewards
                                            Case 4
                                                qfQuery.Source.Source = SourceType.PvpRewardsAlliance
                                                qfQuery.Source.PvpAllianceSource = SelectPvpAllianceSource()
                                            Case 5
                                                qfQuery.Source.Source = SourceType.PvpRewardsHorde
                                                qfQuery.Source.PvpHordeSource = SelectPvpHordeSource()
                                        End Select
                                        Console.Clear()
                                        Exit Do
                                    End If
                                End If
                                Console.Clear()
                                Console.WriteLine("Invalid source.  Please try again.")
                                Console.WriteLine()
                            Loop
                        Case 2
                            Do
                                Console.Clear()
                                Console.WriteLine("Item Type Selection")
                                Console.WriteLine()

                                Console.WriteLine("Select an item type:")
                                Console.WriteLine("0) All Items")
                                Console.WriteLine("1) Weapons")
                                Console.WriteLine("2) Armor")
                                Console.WriteLine("3) Gems")
                                Console.WriteLine("4) Containers")
                                Console.WriteLine("5) Consumables")
                                Console.WriteLine("6) Trade Goods")
                                Console.WriteLine("7) Projectiles")
                                Console.WriteLine("8) Quivers")
                                Console.WriteLine("9) Recipes")
                                Console.WriteLine("10) Reagents")
                                Console.WriteLine("11) Miscellaneous")
                                Console.WriteLine("12) Permanent Enchantments")
                                Console.WriteLine("13) Temporary Enchantments")
                                Console.WriteLine("14) Mounts")
                                Console.WriteLine("15) Small Pets")
                                Console.WriteLine("16) Keys")
                                Console.WriteLine("17) Glyphs")

                                Console.WriteLine()
                                Console.Write(">")

                                Dim strResponse2 As String = Console.ReadLine()
                                If String.IsNullOrEmpty(strResponse2) Then
                                    Console.Clear()
                                    Exit Do
                                End If
                                Dim intResponse2 As Integer
                                If Integer.TryParse(strResponse2, intResponse2) Then
                                    If intResponse2 >= 0 And intResponse2 <= 17 Then
                                        Select Case intResponse2
                                            Case 0
                                                qfQuery.ItemType.ItemType = ItemTypeType.AllItems
                                                qfQuery.ItemType.DesiredBy = SelectDesiredBy()
                                                If (From i In ItemSearch.QueryFilter.ItemTypeFilter.DesiredByWithRole Where i = qfQuery.ItemType.DesiredBy).Count > 0 Then
                                                    qfQuery.ItemType.DesiredByRole = SelectDesiredByRole(qfQuery.ItemType.DesiredBy)
                                                End If
                                                qfQuery.ItemType.RequiredLevelMin = SelectRequiredLevelMin()
                                                qfQuery.ItemType.RequiredLevelMax = SelectRequiredLevelMax(qfQuery.ItemType.RequiredLevelMin)
                                                qfQuery.ItemType.Rarity = SelectRarity()
                                                qfQuery.AdvancedOptions = SelectAdvancedOptions()
                                            Case 1
                                                qfQuery.ItemType.ItemType = ItemTypeType.Weapons
                                                qfQuery.ItemType.DesiredBy = SelectDesiredBy()
                                                If (From i In ItemSearch.QueryFilter.ItemTypeFilter.DesiredByWithRole Where i = qfQuery.ItemType.DesiredBy).Count > 0 Then
                                                    qfQuery.ItemType.DesiredByRole = SelectDesiredByRole(qfQuery.ItemType.DesiredBy)
                                                End If
                                                qfQuery.ItemType.WeaponSlot = SelectWeaponSlot()
                                                qfQuery.ItemType.WeaponType = SelectWeaponType()
                                                qfQuery.ItemType.RequiredLevelMin = SelectRequiredLevelMin()
                                                qfQuery.ItemType.RequiredLevelMax = SelectRequiredLevelMax(qfQuery.ItemType.RequiredLevelMin)
                                                qfQuery.ItemType.Rarity = SelectRarity()
                                                qfQuery.AdvancedOptions = SelectAdvancedOptions()
                                            Case 2
                                                qfQuery.ItemType.ItemType = ItemTypeType.Armor
                                                qfQuery.ItemType.DesiredBy = SelectDesiredBy()
                                                If (From i In ItemSearch.QueryFilter.ItemTypeFilter.DesiredByWithRole Where i = qfQuery.ItemType.DesiredBy).Count > 0 Then
                                                    qfQuery.ItemType.DesiredByRole = SelectDesiredByRole(qfQuery.ItemType.DesiredBy)
                                                End If
                                                qfQuery.ItemType.ArmorSlot = SelectArmorSlot()
                                                qfQuery.ItemType.ArmorType = SelectArmorType()
                                                qfQuery.ItemType.RequiredLevelMin = SelectRequiredLevelMin()
                                                qfQuery.ItemType.RequiredLevelMax = SelectRequiredLevelMax(qfQuery.ItemType.RequiredLevelMin)
                                                qfQuery.ItemType.Rarity = SelectRarity()
                                                qfQuery.AdvancedOptions = SelectAdvancedOptions()
                                            Case 3
                                                qfQuery.ItemType.ItemType = ItemTypeType.Gems
                                                qfQuery.ItemType.Rarity = SelectRarity()
                                                qfQuery.ItemType.GemType = SelectGemType()
                                                qfQuery.ItemType.DesiredBy = SelectDesiredBy()
                                                If (From i In ItemSearch.QueryFilter.ItemTypeFilter.DesiredByWithRole Where i = qfQuery.ItemType.DesiredBy).Count > 0 Then
                                                    qfQuery.ItemType.DesiredByRole = SelectDesiredByRole(qfQuery.ItemType.DesiredBy)
                                                End If
                                                qfQuery.AdvancedOptions = SelectAdvancedOptions()
                                            Case 4
                                                qfQuery.ItemType.ItemType = ItemTypeType.Containers
                                                qfQuery.ItemType.ContainerType = SelectContainerType()
                                            Case 5
                                                qfQuery.ItemType.ItemType = ItemTypeType.Consumables
                                                qfQuery.ItemType.Rarity = SelectRarity()
                                            Case 6
                                                qfQuery.ItemType.ItemType = ItemTypeType.TradeGoods
                                                qfQuery.ItemType.Rarity = SelectRarity()
                                            Case 7
                                                qfQuery.ItemType.ItemType = ItemTypeType.Projectiles
                                                qfQuery.ItemType.ProjectilesType = SelectProjectilesType()
                                                qfQuery.ItemType.Rarity = SelectRarity()
                                            Case 8
                                                qfQuery.ItemType.ItemType = ItemTypeType.Quivers
                                                qfQuery.ItemType.QuiverType = SelectQuiverType()
                                            Case 9
                                                qfQuery.ItemType.ItemType = ItemTypeType.Recipes
                                                qfQuery.ItemType.RecipesType = SelectRecipesType()
                                                qfQuery.ItemType.Rarity = SelectRarity()
                                                qfQuery.ItemType.SkillLevelMin = SelectSkillLevelMin()
                                                qfQuery.ItemType.SkillLevelMax = SelectSkillLevelMax(qfQuery.ItemType.SkillLevelMin)
                                            Case 10
                                                qfQuery.ItemType.ItemType = ItemTypeType.Reagents
                                                qfQuery.ItemType.Rarity = SelectRarity()
                                            Case 11
                                                qfQuery.ItemType.ItemType = ItemTypeType.Miscellaneous
                                                qfQuery.ItemType.Rarity = SelectRarity()
                                            Case 12
                                                qfQuery.ItemType.ItemType = ItemTypeType.EnchantmentsPermanent
                                                qfQuery.ItemType.PermanentEnchantmentSlot = SelectPermanentEnchantmentSlot()
                                                qfQuery.ItemType.Rarity = SelectRarity()
                                                qfQuery.AdvancedOptions = SelectAdvancedOptions()
                                            Case 13
                                                qfQuery.ItemType.ItemType = ItemTypeType.EnchantmentsTemporary
                                                qfQuery.ItemType.Rarity = SelectRarity()
                                                qfQuery.AdvancedOptions = SelectAdvancedOptions()
                                            Case 14
                                                qfQuery.ItemType.ItemType = ItemTypeType.Mounts
                                            Case 15
                                                qfQuery.ItemType.ItemType = ItemTypeType.SmallPets
                                            Case 16
                                                qfQuery.ItemType.ItemType = ItemTypeType.Keys
                                            Case 17
                                                qfQuery.ItemType.ItemType = ItemTypeType.Glyphs
                                                qfQuery.ItemType.DesiredBy = SelectDesiredBy()
                                                If (From i In ItemSearch.QueryFilter.ItemTypeFilter.DesiredByWithRole Where i = qfQuery.ItemType.DesiredBy).Count > 0 Then
                                                    qfQuery.ItemType.DesiredByRole = SelectDesiredByRole(qfQuery.ItemType.DesiredBy)
                                                End If
                                        End Select
                                        Console.Clear()
                                        Exit Do
                                    End If
                                End If
                                Console.Clear()
                                Console.WriteLine("Invalid item type.  Please try again.")
                                Console.WriteLine()
                            Loop
                        Case 3
                            Console.Clear()
                            Console.WriteLine("Search Terms")
                            Console.WriteLine()
                            Console.WriteLine("Enter your search terms:")

                            Console.Write(">")
                            qfQuery.SearchQuery = Console.ReadLine()
                            Console.Clear()
                        Case 4
                            Exit Do
                    End Select
                End If
            End If
        Loop

        ' Perform search
        Dim isSearch As New ItemSearch()
        isSearch.Filter = qfQuery
        isSearch.Search()

        ' Return results
        Console.Clear()
        If isSearch.Items.Count = 0 Then
            Console.WriteLine("Your query did not produce any results.")
            Console.WriteLine()
        Else
            Console.WriteLine("Search Results")
            Console.WriteLine()
            For Each iItem As ItemSearch.Item In isSearch.Items.OrderByDescending(Function(i) i.Relevance)
                Console.WriteLine("{0}) {1}", iItem.ID, iItem.Name)
            Next
        End If
        Console.WriteLine("Press any key to continue.")
        Console.ReadKey(True)
    End Sub

    Private Function SelectDungeon(ByRef dDungeons As Dungeons) As String
        Console.Clear()
        Console.WriteLine("Dungeon Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a dungeon key")
            Console.WriteLine("  Or press enter to exit.")

            For Each dDungeon As Dungeons.Dungeon In dDungeons.Dungeons
                Console.WriteLine("{0}) {1}", dDungeon.Key, dDungeon.Name)
            Next
            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then
                Return "all"
            End If
            Dim varDungeons = (From d In dDungeons.Dungeons Where d.Key = strResponse)
            If varDungeons.Count > 0 Then
                Dim dDungeon As Dungeons.Dungeon = varDungeons.First()
                Return strResponse
            End If
            Console.Clear()
            Console.WriteLine("Invalid dungeon key.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectBoss(ByVal dDungeon As Dungeons.Dungeon) As Integer
        Console.Clear()
        Console.WriteLine("Boss Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a boss ID")
            Console.WriteLine("  Or press enter to exit.")

            For Each bBoss As Dungeons.Boss In dDungeon.Bosses
                Console.WriteLine("{0}) {1}", bBoss.ID, bBoss.Name)
            Next
            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                Dim varBosses = (From b In dDungeon.Bosses Where b.ID = strResponse)
                If varBosses.Count > 0 Then
                    Return varBosses.First().ID
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid boss ID.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectDifficulty() As DifficultyType
        Console.Clear()
        Console.WriteLine("Dungeon Difficulty Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a dungeon difficulty")

            Console.WriteLine("0) Normal & Heroic")
            Console.WriteLine("1) Normal Only")
            Console.WriteLine("2) Heroic Only")

            Console.WriteLine()
            Console.Write(">")
            Dim ckiKey As ConsoleKeyInfo = Console.ReadKey()
            Console.WriteLine()

            Dim intKey As Integer
            If Integer.TryParse(ckiKey.KeyChar, intKey) Then
                If intKey >= 0 And intKey <= 2 Then
                    Return CType(intKey, DifficultyType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid difficulty.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectFaction(ByVal fFactions As Factions) As Integer
        Console.Clear()
        Console.WriteLine("Reputation Faction Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a faction ID")
            Console.WriteLine("  Or press enter to exit.")

            Console.WriteLine("0) All Factions")
            For Each fFaction As Factions.Faction In fFactions.Factions
                Console.WriteLine("{0}) {1}", fFaction.ID, fFaction.Name)
            Next
            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse = 0 OrElse (From f In fFactions.Factions Where f.ID = intResponse).Count > 0 Then
                    Return intResponse
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid faction ID.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectPvpAllianceSource() As PvpAllianceSourceType
        Console.Clear()
        Console.WriteLine("Alliance PvP Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a PvP source")
            Console.WriteLine("  Or press enter to exit.")

            Console.WriteLine("0) All Pvp Sources")
            Console.WriteLine("1) Wintergrasp")
            Console.WriteLine("2) Arena Season 6")
            Console.WriteLine("3) Arena Season 5")
            Console.WriteLine("4) Arena Season 4")
            Console.WriteLine("5) Honor Rewards")
            Console.WriteLine("6) Arathi Basin")
            Console.WriteLine("7) Alterac Valley")
            Console.WriteLine("8) Warsong Gulch")
            Console.WriteLine("9) Halaa")
            Console.WriteLine("10) Honor Hold")
            Console.WriteLine("11) Terokkar")
            Console.WriteLine("12) Zangarmarsh")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 12 Then
                    Return CType(intResponse, PvpAllianceSourceType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid source.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectPvpHordeSource() As PvpHordeSourceType
        Console.Clear()
        Console.WriteLine("Horde PvP Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a PvP source")
            Console.WriteLine("  Or press enter to exit.")

            Console.WriteLine("0) All Pvp Sources")
            Console.WriteLine("1) Wintergrasp")
            Console.WriteLine("2) Arena Season 6")
            Console.WriteLine("3) Arena Season 5")
            Console.WriteLine("4) Arena Season 4")
            Console.WriteLine("5) Honor Rewards")
            Console.WriteLine("6) Arathi Basin")
            Console.WriteLine("7) Alterac Valley")
            Console.WriteLine("8) Warsong Gulch")
            Console.WriteLine("9) Halaa")
            Console.WriteLine("10) Thrallmar")
            Console.WriteLine("11) Terokkar")
            Console.WriteLine("12) Zangarmarsh")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 12 Then
                    Return CType(intResponse, PvpHordeSourceType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid source.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectDesiredBy() As DesiredByType
        Console.Clear()
        Console.WriteLine("Desired By Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a desired class")

            Console.WriteLine("0) Any Class")
            Console.WriteLine("6) Death Knight")
            Console.WriteLine("11) Druid")
            Console.WriteLine("3) Hunter")
            Console.WriteLine("8) Mage")
            Console.WriteLine("2) Paladin")
            Console.WriteLine("5) Priest")
            Console.WriteLine("4) Rogue")
            Console.WriteLine("7) Shaman")
            Console.WriteLine("9) Warlock")
            Console.WriteLine("1) Warrior")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 11 And intResponse <> 10 Then
                    Return CType(intResponse, DesiredByType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid desired by class.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectDesiredByRole(ByVal dbClass As DesiredByType) As DesiredByRoleType
        Console.Clear()
        Console.WriteLine("Desired By Role Selection")
        Console.WriteLine()
        Do
            Dim lstArray As New List(Of Integer)

            Console.WriteLine("Select a desired role")

            Console.WriteLine("0) Any Type")
            lstArray.Add(0)
            If (From i In ItemSearch.QueryFilter.ItemTypeFilter.DesiredByWithRoleTank Where i = dbClass).Count > 0 Then
                Console.WriteLine("1) Tank")
                lstArray.Add(1)
            End If
            If (From i In ItemSearch.QueryFilter.ItemTypeFilter.DesiredByWithRoleMeleeDPS Where i = dbClass).Count > 0 Then
                Console.WriteLine("2) Melee DPS")
                lstArray.Add(2)
            End If
            If (From i In ItemSearch.QueryFilter.ItemTypeFilter.DesiredByWithRoleCasterDPS Where i = dbClass).Count > 0 Then
                Console.WriteLine("3) Caster DPS")
                lstArray.Add(3)
            End If
            If (From i In ItemSearch.QueryFilter.ItemTypeFilter.DesiredByWithRoleHealer Where i = dbClass).Count > 0 Then
                Console.WriteLine("4) Healer")
                lstArray.Add(4)
            End If
            If (From i In ItemSearch.QueryFilter.ItemTypeFilter.DesiredByWithRolePlusDamageOnly Where i = dbClass).Count > 0 Then
                Console.WriteLine("5) +Damage Only")
                lstArray.Add(5)
            End If
            If (From i In ItemSearch.QueryFilter.ItemTypeFilter.DesiredByWithRolePlusDamageAndCrit Where i = dbClass).Count > 0 Then
                Console.WriteLine("6) +Damage & Crit")
                lstArray.Add(6)
            End If

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If (From i In lstArray Where i = intResponse).Count > 0 Then
                    Return CType(intResponse, DesiredByRoleType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid desired by role.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectWeaponSlot() As WeaponSlotType
        Console.Clear()
        Console.WriteLine("Weapon Slot Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a weapon slot")

            Console.WriteLine("0) All Slots")
            Console.WriteLine("1) Main Hand")
            Console.WriteLine("2) Off Hand")
            Console.WriteLine("3) Main or Off Hand")
            Console.WriteLine("4) Two Handed")
            Console.WriteLine("5) Ranged")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 5 Then
                    Return CType(intResponse, WeaponSlotType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid weapon slot.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectWeaponType() As WeaponTypeType
        Console.Clear()
        Console.WriteLine("Weapon Type Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a weapon type")

            Console.WriteLine("0) All Weapon Types")
            Console.WriteLine("1) One Handed Axes")
            Console.WriteLine("2) Two Handed Axes")
            Console.WriteLine("3) Bows")
            Console.WriteLine("4) Guns")
            Console.WriteLine("5) One Handed Maces")
            Console.WriteLine("6) Two Handed Maces")
            Console.WriteLine("7) Polearms")
            Console.WriteLine("8) One Handed Swords")
            Console.WriteLine("9) Two Handed Swords")
            Console.WriteLine("10) Fist Weapons")
            Console.WriteLine("11) Miscellaneous")
            Console.WriteLine("12) Daggers")
            Console.WriteLine("13) Thrown")
            Console.WriteLine("14) Crossbows")
            Console.WriteLine("15) Wands")
            Console.WriteLine("16) Fishing Pole")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 16 Then
                    Return CType(intResponse, WeaponTypeType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid weapon type.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Function SelectRequiredLevelMin() As Integer
        Console.Clear()
        Console.WriteLine("Minimum Required Level")
        Console.WriteLine()
        Do
            Console.WriteLine("Enter the minimum required level")
            Console.WriteLine("  or press enter to exit")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 1 And intResponse <= 80 Then
                    Return intResponse
                End If
            End If
            Console.Clear()
            Console.WriteLine("The level must be between 1 and 80.")
            Console.WriteLine()
        Loop
    End Function

    Function SelectRequiredLevelMax(ByVal intRequiredLevelMin As Integer) As Integer
        Console.Clear()
        Console.WriteLine("Maximum Required Level")
        Console.WriteLine()
        Do
            Console.WriteLine("Enter the maximum required level")
            Console.WriteLine("  or press enter to exit")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 1 And intResponse <= 80 Then
                    If intRequiredLevelMin = 0 Or intResponse >= intRequiredLevelMin Then
                        Return intResponse
                    End If
                End If
            End If
            Console.Clear()
            Console.WriteLine("The level must be between {0} and 80.", If(intRequiredLevelMin = 0, 1, intRequiredLevelMin))
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectRarity() As RarityType
        Console.Clear()
        Console.WriteLine("Rarity Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a minimum rarity")
            Console.WriteLine("  or press enter to exit")

            Console.WriteLine("0) Poor")
            Console.WriteLine("1) Common")
            Console.WriteLine("2) Uncommon")
            Console.WriteLine("3) Rare")
            Console.WriteLine("4) Epic")
            Console.WriteLine("5) Legendary")
            Console.WriteLine("6) Heirloom")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return -1
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 6 Then
                    Return CType(intResponse, RarityType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid rarity.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectArmorSlot() As ArmorSlotType
        Console.Clear()
        Console.WriteLine("Armor Slot Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select an armor slot")

            Console.WriteLine("0) All Slots")
            Console.WriteLine("1) Head")
            Console.WriteLine("2) Neck")
            Console.WriteLine("3) Shoulders")
            Console.WriteLine("4) Back")
            Console.WriteLine("5) Chest")
            Console.WriteLine("6) Shirt")
            Console.WriteLine("7) Wrists")
            Console.WriteLine("8) Hands")
            Console.WriteLine("9) Waist")
            Console.WriteLine("10) Legs")
            Console.WriteLine("11) Feet")
            Console.WriteLine("12) Finger")
            Console.WriteLine("13) Trinket")
            Console.WriteLine("14) Off Hand Frill")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 14 Then
                    Return CType(intResponse, ArmorSlotType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid armor slot.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectArmorType() As ArmorTypeType
        Console.Clear()
        Console.WriteLine("Armor Type Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select an armor type")

            Console.WriteLine("0) All Armor Types")
            Console.WriteLine("1) Cloth")
            Console.WriteLine("2) Leather")
            Console.WriteLine("3) Mail")
            Console.WriteLine("4) Plate")
            Console.WriteLine("5) Shield")
            Console.WriteLine("6) Idol")
            Console.WriteLine("7) Libram")
            Console.WriteLine("8) Totem")
            Console.WriteLine("9) Sigil")
            Console.WriteLine("10) Miscellaneous")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 10 Then
                    Return CType(intResponse, ArmorTypeType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid armor type.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectGemType() As GemTypeType
        Console.Clear()
        Console.WriteLine("Gem Type Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a gem type")

            Console.WriteLine("0) All Gem Types")
            Console.WriteLine("1) Blue")
            Console.WriteLine("2) Red")
            Console.WriteLine("3) Yellow")
            Console.WriteLine("4) Meta")
            Console.WriteLine("5) Green")
            Console.WriteLine("6) Orange")
            Console.WriteLine("7) Purple")
            Console.WriteLine("8) Prismatic")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 8 Then
                    Return CType(intResponse, ArmorTypeType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid gem type.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectContainerType() As BagTypeType
        Console.Clear()
        Console.WriteLine("Bag Type Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a bag type")

            Console.WriteLine("0) All Bags")
            Console.WriteLine("1) Bag")
            Console.WriteLine("2) Soul Bag")
            Console.WriteLine("3) Herb Bag")
            Console.WriteLine("4) Enchanting Bag")
            Console.WriteLine("5) Engineering Bag")
            Console.WriteLine("6) Gem Bag")
            Console.WriteLine("7) Mining Bag")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 7 Then
                    Return CType(intResponse, BagTypeType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid bag type.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectProjectilesType() As ProjectileTypeType
        Console.Clear()
        Console.WriteLine("Projectile Type Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a projectile type")

            Console.WriteLine("0) All Projectiles")
            Console.WriteLine("1) Arrow")
            Console.WriteLine("2) Bullet")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 2 Then
                    Return CType(intResponse, ProjectileTypeType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid projectile type.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectQuiverType() As QuiverTypeType
        Console.Clear()
        Console.WriteLine("Quiver Type Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a quiver type")

            Console.WriteLine("0) All Quivers")
            Console.WriteLine("1) Quiver")
            Console.WriteLine("2) Ammo Pouch")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 2 Then
                    Return CType(intResponse, QuiverTypeType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid quiver type.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectRecipesType() As RecipesTypeType
        Console.Clear()
        Console.WriteLine("Recipe Type Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a recipe type")

            Console.WriteLine("0) All Recipes")
            Console.WriteLine("1) Books")
            Console.WriteLine("2) Leatherworking")
            Console.WriteLine("3) Tailoring")
            Console.WriteLine("4) Engineering")
            Console.WriteLine("5) Blacksmithing")
            Console.WriteLine("6) Cooking")
            Console.WriteLine("7) Alchemy")
            Console.WriteLine("8) First Aid")
            Console.WriteLine("9) Enchanting")
            Console.WriteLine("10) Fishing")
            Console.WriteLine("11) Jewelcrafting")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 11 Then
                    Return CType(intResponse, RecipesTypeType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid recipe type.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Function SelectSkillLevelMin() As Integer
        Console.Clear()
        Console.WriteLine("Minimum Skill Level")
        Console.WriteLine()
        Do
            Console.WriteLine("Enter the minimum skill level")
            Console.WriteLine("  or press enter to exit")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 1 And intResponse <= 450 Then
                    Return intResponse
                End If
            End If
            Console.Clear()
            Console.WriteLine("The level must be between 1 and 450.")
            Console.WriteLine()
        Loop
    End Function

    Function SelectSkillLevelMax(ByVal intSkillLevelMin As Integer) As Integer
        Console.Clear()
        Console.WriteLine("Maximum Skill Level")
        Console.WriteLine()
        Do
            Console.WriteLine("Enter the maximum skill level")
            Console.WriteLine("  or press enter to exit")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 1 And intResponse <= 450 Then
                    If intSkillLevelMin = 0 Or intResponse >= intSkillLevelMin Then
                        Return intResponse
                    End If
                End If
            End If
            Console.Clear()
            Console.WriteLine("The level must be between {0} and 450.", If(intSkillLevelMin = 0, 1, intSkillLevelMin))
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectPermanentEnchantmentSlot() As PermanentEnchantmentSlotType
        Console.Clear()
        Console.WriteLine("Permanent Enchantment Slot Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select a permanent enchantment slot")

            Console.WriteLine("0) All Slots")
            Console.WriteLine("1) Head")
            Console.WriteLine("3) Shoulders")
            Console.WriteLine("4) Back")
            Console.WriteLine("5) Chest")
            Console.WriteLine("7) Wrists")
            Console.WriteLine("8) Hands")
            Console.WriteLine("10) Legs")
            Console.WriteLine("11) Feet")
            Console.WriteLine("12) Finger")
            Console.WriteLine("15) Weapon")
            Console.WriteLine("16) Shield")

            Console.WriteLine()
            Console.Write(">")

            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return 0
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 16 And intResponse <> 2 And intResponse <> 6 And intResponse <> 9 And intResponse <> 13 And intResponse <> 14 Then
                    Return CType(intResponse, RecipesTypeType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid permanent enchantment slot.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectAdvancedOptions() As List(Of ItemSearch.QueryFilter.AdvancedOptionsFilter)
        Console.Clear()
        Console.WriteLine("Advanced Options Filter Selection")
        Console.WriteLine()

        Dim lstFilter As New List(Of ItemSearch.QueryFilter.AdvancedOptionsFilter)

        Do
            Console.WriteLine("Select a filter to delete it")
            Console.WriteLine("  or press enter to accept the current filters")
            Console.WriteLine("  or type ""add"" to add a new filter")

            Dim intCount As Integer = 0
            For Each aofFilter In lstFilter
                intCount += 1
                If aofFilter.AdvancedOptions <= AdvancedOptionsType.General_HitRating Then
                    Dim strOperator As String = ""
                    Select Case aofFilter.Operator
                        Case AdvancedOptionsOperatorType.EqualTo
                            strOperator = "="
                        Case AdvancedOptionsOperatorType.GreaterThan
                            strOperator = ">"
                        Case AdvancedOptionsOperatorType.GreaterThanEqualTo
                            strOperator = ">="
                        Case AdvancedOptionsOperatorType.LessThan
                            strOperator = "<"
                        Case AdvancedOptionsOperatorType.LessThanEqualTo
                            strOperator = "<="
                    End Select
                    Console.WriteLine("{0}) {1} {2} {3}", intCount, [Enum].GetName(GetType(AdvancedOptionsType), aofFilter.AdvancedOptions), strOperator, aofFilter.Range)
                Else
                    Console.WriteLine("{0}) {1}", intCount, [Enum].GetName(GetType(AdvancedOptionsType), aofFilter.AdvancedOptions))
                End If
            Next
            Console.WriteLine()

            Console.Write(">")
            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return lstFilter
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 1 And intResponse <= intCount Then
                    lstFilter.RemoveAt(intResponse - 1)
                    Console.Clear()
                    Continue Do
                End If
            ElseIf strResponse.ToLower() = "add" Then
                Dim aofFilter As ItemSearch.QueryFilter.AdvancedOptionsFilter = SelectAdvancedFilter()
                If aofFilter IsNot Nothing Then lstFilter.Add(aofFilter)
                Console.Clear()
                Continue Do
            End If
            Console.Clear()
            Console.WriteLine("Invalid filter.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectAdvancedFilter() As ItemSearch.QueryFilter.AdvancedOptionsFilter
        Console.Clear()
        Console.WriteLine("Advanced Options Filter Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select an advanced option")
            Console.WriteLine("  Or press enter to exit")
            Console.WriteLine()
            Console.WriteLine("Base Stat Bonuses")
            Console.WriteLine("0) Strength")
            Console.WriteLine("1) Agility")
            Console.WriteLine("2) Stamina")
            Console.WriteLine("3) Intellect")
            Console.WriteLine("4) Spirit")
            Console.WriteLine()
            Console.WriteLine("General Bonuses")
            Console.WriteLine("5) Crit Rating")
            Console.WriteLine("6) Hit Rating")
            Console.WriteLine("7) Haste Rating")
            Console.WriteLine()
            Console.WriteLine("Physical Combat Bonsues")
            Console.WriteLine("8) Attack Power")
            Console.WriteLine("9) Feral Attack Power")
            Console.WriteLine("10) Armor Penetration")
            Console.WriteLine("11) Expertise Rating")
            Console.WriteLine()
            Console.WriteLine("Spell Bonuses")
            Console.WriteLine("12) Spell Power")
            Console.WriteLine("13) Spell Crit Rating")
            Console.WriteLine("14) Spell Hit Rating")
            Console.WriteLine("15) Penetration")
            Console.WriteLine("16) Mana Regen")
            Console.WriteLine("17) Spell Haste Rating")
            Console.WriteLine("18) Arcane Damage")
            Console.WriteLine("19) Holy Damage")
            Console.WriteLine("20) Shadow Damage")
            Console.WriteLine("21) Nature Damage")
            Console.WriteLine("22) Frost Damage")
            Console.WriteLine("23) Fire Damage")
            Console.WriteLine()
            Console.WriteLine("Defense Bonuses")
            Console.WriteLine("24) Armor")
            Console.WriteLine("25) Block Rating")
            Console.WriteLine("26) Block Value")
            Console.WriteLine("27) Defense Rating")
            Console.WriteLine("28) Dodge Rating")
            Console.WriteLine("29) Parry Rating")
            Console.WriteLine("30) Health Regen")
            Console.WriteLine("31) Resilience")
            Console.WriteLine()
            Console.WriteLine("Resistance Bonuses")
            Console.WriteLine("32) Arcane Resist")
            Console.WriteLine("33) Shadow Resist")
            Console.WriteLine("34) Nature Resist")
            Console.WriteLine("35) Frost Resist")
            Console.WriteLine("36) Fire Resist")
            Console.WriteLine()
            Console.WriteLine("Weapon Stats")
            Console.WriteLine("37) DPS")
            Console.WriteLine("38) Min Damage")
            Console.WriteLine("39) Max Damage")
            Console.WriteLine("40) Speed")
            Console.WriteLine()
            Console.WriteLine("General Bonuses")
            Console.WriteLine("41) Bind on Pickup")
            Console.WriteLine("42) Bind on Equip")
            Console.WriteLine("43) Bind on Use")
            Console.WriteLine("44) Unique")
            Console.WriteLine("45) Unique Equipped")
            Console.WriteLine()
            Console.WriteLine("Has Spell Effect")
            Console.WriteLine("46) Chance to Resist")
            Console.WriteLine("47) Avoid Interruption")
            Console.WriteLine("48) Chance on Hit or Cast")
            Console.WriteLine("49) Dispel Effects")
            Console.WriteLine("50) Reduce Cooldown")
            Console.WriteLine("51) Reduce Cast Time")
            Console.WriteLine("52) Reduce Spell Cost")
            Console.WriteLine("53) Increase Duration")
            Console.WriteLine("54) Increase Range")
            Console.WriteLine("55) Reduce Threat")
            Console.WriteLine("56) Group Buff")
            Console.WriteLine("57) Summon Creature")
            Console.WriteLine()

            Console.Write(">")
            Dim strResponse As String = Console.ReadLine()
            If String.IsNullOrEmpty(strResponse) Then Return Nothing
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 40 Then
                    Dim aofFilter As New ItemSearch.QueryFilter.AdvancedOptionsFilter()
                    aofFilter.AdvancedOptions = CType(intResponse, AdvancedOptionsType)
                    aofFilter.Operator = SelectAdvancedFilterOperator()
                    aofFilter.Range = SelectAdvancedFilterRange()
                    Return aofFilter
                ElseIf intResponse >= 41 And intResponse <= 57 Then
                    Dim aofFilter As New ItemSearch.QueryFilter.AdvancedOptionsFilter()
                    aofFilter.AdvancedOptions = CType(intResponse, AdvancedOptionsType)
                    Return aofFilter
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid gem type.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectAdvancedFilterOperator() As AdvancedOptionsOperatorType
        Console.Clear()
        Console.WriteLine("Advanced Options Filter Operator Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Select an operator")
            Console.WriteLine()
            Console.WriteLine("0) >")
            Console.WriteLine("1) >=")
            Console.WriteLine("2) =")
            Console.WriteLine("3) <")
            Console.WriteLine("4) <=")
            Console.WriteLine()

            Console.Write(">")
            Dim strResponse As String = Console.ReadLine()
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                If intResponse >= 0 And intResponse <= 4 Then
                    Return CType(intResponse, AdvancedOptionsOperatorType)
                End If
            End If
            Console.Clear()
            Console.WriteLine("Invalid operator.  Please try again.")
            Console.WriteLine()
        Loop
    End Function

    Private Function SelectAdvancedFilterRange() As Integer
        Console.Clear()
        Console.WriteLine("Advanced Options Filter Range Selection")
        Console.WriteLine()
        Do
            Console.WriteLine("Enter a range value to compare to")

            Console.Write(">")
            Dim strResponse As String = Console.ReadLine()
            Dim intResponse As Integer
            If Integer.TryParse(strResponse, intResponse) Then
                Return intResponse
            End If
            Console.Clear()
            Console.WriteLine("You must enter a value.")
            Console.WriteLine()
        Loop
    End Function

End Module
